mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-140550: Initial implementation of PEP 793 – PyModExport (GH-140556)
Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Kumar Aditya <kumaraditya@python.org>
This commit is contained in:
parent
f2bce51b98
commit
589a03a8ce
32 changed files with 1494 additions and 236 deletions
6
Doc/data/stable_abi.dat
generated
6
Doc/data/stable_abi.dat
generated
|
|
@ -425,6 +425,7 @@ func,PyLong_FromUnsignedNativeBytes,3.14,,
|
||||||
func,PyLong_FromVoidPtr,3.2,,
|
func,PyLong_FromVoidPtr,3.2,,
|
||||||
func,PyLong_GetInfo,3.2,,
|
func,PyLong_GetInfo,3.2,,
|
||||||
data,PyLong_Type,3.2,,
|
data,PyLong_Type,3.2,,
|
||||||
|
macro,PyMODEXPORT_FUNC,3.15,,
|
||||||
data,PyMap_Type,3.2,,
|
data,PyMap_Type,3.2,,
|
||||||
func,PyMapping_Check,3.2,,
|
func,PyMapping_Check,3.2,,
|
||||||
func,PyMapping_GetItemString,3.2,,
|
func,PyMapping_GetItemString,3.2,,
|
||||||
|
|
@ -471,8 +472,10 @@ func,PyModule_AddObjectRef,3.10,,
|
||||||
func,PyModule_AddStringConstant,3.2,,
|
func,PyModule_AddStringConstant,3.2,,
|
||||||
func,PyModule_AddType,3.10,,
|
func,PyModule_AddType,3.10,,
|
||||||
func,PyModule_Create2,3.2,,
|
func,PyModule_Create2,3.2,,
|
||||||
|
func,PyModule_Exec,3.15,,
|
||||||
func,PyModule_ExecDef,3.7,,
|
func,PyModule_ExecDef,3.7,,
|
||||||
func,PyModule_FromDefAndSpec2,3.7,,
|
func,PyModule_FromDefAndSpec2,3.7,,
|
||||||
|
func,PyModule_FromSlotsAndSpec,3.15,,
|
||||||
func,PyModule_GetDef,3.2,,
|
func,PyModule_GetDef,3.2,,
|
||||||
func,PyModule_GetDict,3.2,,
|
func,PyModule_GetDict,3.2,,
|
||||||
func,PyModule_GetFilename,3.2,,
|
func,PyModule_GetFilename,3.2,,
|
||||||
|
|
@ -480,6 +483,8 @@ func,PyModule_GetFilenameObject,3.2,,
|
||||||
func,PyModule_GetName,3.2,,
|
func,PyModule_GetName,3.2,,
|
||||||
func,PyModule_GetNameObject,3.7,,
|
func,PyModule_GetNameObject,3.7,,
|
||||||
func,PyModule_GetState,3.2,,
|
func,PyModule_GetState,3.2,,
|
||||||
|
func,PyModule_GetStateSize,3.15,,
|
||||||
|
func,PyModule_GetToken,3.15,,
|
||||||
func,PyModule_New,3.2,,
|
func,PyModule_New,3.2,,
|
||||||
func,PyModule_NewObject,3.7,,
|
func,PyModule_NewObject,3.7,,
|
||||||
func,PyModule_SetDocString,3.7,,
|
func,PyModule_SetDocString,3.7,,
|
||||||
|
|
@ -738,6 +743,7 @@ func,PyType_GetFlags,3.2,,
|
||||||
func,PyType_GetFullyQualifiedName,3.13,,
|
func,PyType_GetFullyQualifiedName,3.13,,
|
||||||
func,PyType_GetModule,3.10,,
|
func,PyType_GetModule,3.10,,
|
||||||
func,PyType_GetModuleByDef,3.13,,
|
func,PyType_GetModuleByDef,3.13,,
|
||||||
|
func,PyType_GetModuleByToken,3.15,,
|
||||||
func,PyType_GetModuleName,3.13,,
|
func,PyType_GetModuleName,3.13,,
|
||||||
func,PyType_GetModuleState,3.10,,
|
func,PyType_GetModuleState,3.10,,
|
||||||
func,PyType_GetName,3.11,,
|
func,PyType_GetName,3.11,,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
inside the Python core, they are private to the core.
|
inside the Python core, they are private to the core.
|
||||||
If in an extension module, it may be declared with
|
If in an extension module, it may be declared with
|
||||||
external linkage depending on the platform.
|
external linkage depending on the platform.
|
||||||
|
PyMODEXPORT_FUNC: Like PyMODINIT_FUNC, but for a slots array
|
||||||
|
|
||||||
As a number of platforms support/require "__declspec(dllimport/dllexport)",
|
As a number of platforms support/require "__declspec(dllimport/dllexport)",
|
||||||
we support a HAVE_DECLSPEC_DLL macro to save duplication.
|
we support a HAVE_DECLSPEC_DLL macro to save duplication.
|
||||||
|
|
@ -62,9 +63,9 @@
|
||||||
/* module init functions inside the core need no external linkage */
|
/* module init functions inside the core need no external linkage */
|
||||||
/* except for Cygwin to handle embedding */
|
/* except for Cygwin to handle embedding */
|
||||||
# if defined(__CYGWIN__)
|
# if defined(__CYGWIN__)
|
||||||
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
|
# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL
|
||||||
# else /* __CYGWIN__ */
|
# else /* __CYGWIN__ */
|
||||||
# define PyMODINIT_FUNC PyObject*
|
# define _PyINIT_FUNC_DECLSPEC
|
||||||
# endif /* __CYGWIN__ */
|
# endif /* __CYGWIN__ */
|
||||||
# else /* Py_BUILD_CORE */
|
# else /* Py_BUILD_CORE */
|
||||||
/* Building an extension module, or an embedded situation */
|
/* Building an extension module, or an embedded situation */
|
||||||
|
|
@ -78,9 +79,9 @@
|
||||||
# define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE
|
# define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE
|
||||||
/* module init functions outside the core must be exported */
|
/* module init functions outside the core must be exported */
|
||||||
# if defined(__cplusplus)
|
# if defined(__cplusplus)
|
||||||
# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
|
# define _PyINIT_FUNC_DECLSPEC extern "C" Py_EXPORTED_SYMBOL
|
||||||
# else /* __cplusplus */
|
# else /* __cplusplus */
|
||||||
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
|
# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL
|
||||||
# endif /* __cplusplus */
|
# endif /* __cplusplus */
|
||||||
# endif /* Py_BUILD_CORE */
|
# endif /* Py_BUILD_CORE */
|
||||||
# endif /* HAVE_DECLSPEC_DLL */
|
# endif /* HAVE_DECLSPEC_DLL */
|
||||||
|
|
@ -93,13 +94,15 @@
|
||||||
#ifndef PyAPI_DATA
|
#ifndef PyAPI_DATA
|
||||||
# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE
|
# define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE
|
||||||
#endif
|
#endif
|
||||||
#ifndef PyMODINIT_FUNC
|
#ifndef _PyINIT_FUNC_DECLSPEC
|
||||||
# if defined(__cplusplus)
|
# if defined(__cplusplus)
|
||||||
# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
|
# define _PyINIT_FUNC_DECLSPEC extern "C" Py_EXPORTED_SYMBOL
|
||||||
# else /* __cplusplus */
|
# else /* __cplusplus */
|
||||||
# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
|
# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL
|
||||||
# endif /* __cplusplus */
|
# endif /* __cplusplus */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PyMODINIT_FUNC _PyINIT_FUNC_DECLSPEC PyObject*
|
||||||
|
#define PyMODEXPORT_FUNC _PyINIT_FUNC_DECLSPEC PyModuleDef_Slot*
|
||||||
|
|
||||||
#endif /* Py_EXPORTS_H */
|
#endif /* Py_EXPORTS_H */
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,11 @@ typedef enum ext_module_origin {
|
||||||
_Py_ext_module_origin_DYNAMIC = 3,
|
_Py_ext_module_origin_DYNAMIC = 3,
|
||||||
} _Py_ext_module_origin;
|
} _Py_ext_module_origin;
|
||||||
|
|
||||||
|
struct hook_prefixes {
|
||||||
|
const char *const init_prefix;
|
||||||
|
const char *const export_prefix;
|
||||||
|
};
|
||||||
|
|
||||||
/* Input for loading an extension module. */
|
/* Input for loading an extension module. */
|
||||||
struct _Py_ext_module_loader_info {
|
struct _Py_ext_module_loader_info {
|
||||||
PyObject *filename;
|
PyObject *filename;
|
||||||
|
|
@ -40,7 +45,7 @@ struct _Py_ext_module_loader_info {
|
||||||
* depending on if it's builtin or not. */
|
* depending on if it's builtin or not. */
|
||||||
PyObject *path;
|
PyObject *path;
|
||||||
_Py_ext_module_origin origin;
|
_Py_ext_module_origin origin;
|
||||||
const char *hook_prefix;
|
const struct hook_prefixes *hook_prefixes;
|
||||||
const char *newcontext;
|
const char *newcontext;
|
||||||
};
|
};
|
||||||
extern void _Py_ext_module_loader_info_clear(
|
extern void _Py_ext_module_loader_info_clear(
|
||||||
|
|
@ -62,7 +67,9 @@ extern int _Py_ext_module_loader_info_init_from_spec(
|
||||||
PyObject *spec);
|
PyObject *spec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The result from running an extension module's init function. */
|
/* The result from running an extension module's init function.
|
||||||
|
* Not used for modules defined via PyModExport (slots array).
|
||||||
|
*/
|
||||||
struct _Py_ext_module_loader_result {
|
struct _Py_ext_module_loader_result {
|
||||||
PyModuleDef *def;
|
PyModuleDef *def;
|
||||||
PyObject *module;
|
PyObject *module;
|
||||||
|
|
@ -89,10 +96,11 @@ extern void _Py_ext_module_loader_result_apply_error(
|
||||||
|
|
||||||
/* The module init function. */
|
/* The module init function. */
|
||||||
typedef PyObject *(*PyModInitFunction)(void);
|
typedef PyObject *(*PyModInitFunction)(void);
|
||||||
|
typedef PyModuleDef_Slot *(*PyModExportFunction)(void);
|
||||||
#ifdef HAVE_DYNAMIC_LOADING
|
#ifdef HAVE_DYNAMIC_LOADING
|
||||||
extern PyModInitFunction _PyImport_GetModInitFunc(
|
extern int _PyImport_GetModuleExportHooks(
|
||||||
struct _Py_ext_module_loader_info *info,
|
struct _Py_ext_module_loader_info *info,
|
||||||
FILE *fp);
|
FILE *fp, PyModInitFunction *modinit, PyModExportFunction *modexport);
|
||||||
#endif
|
#endif
|
||||||
extern int _PyImport_RunModInitFunc(
|
extern int _PyImport_RunModInitFunc(
|
||||||
PyModInitFunction p0,
|
PyModInitFunction p0,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
#ifndef Py_INTERNAL_MODULEOBJECT_H
|
#ifndef Py_INTERNAL_MODULEOBJECT_H
|
||||||
#define Py_INTERNAL_MODULEOBJECT_H
|
#define Py_INTERNAL_MODULEOBJECT_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -16,32 +19,49 @@ extern int _PyModule_IsPossiblyShadowing(PyObject *);
|
||||||
|
|
||||||
extern int _PyModule_IsExtension(PyObject *obj);
|
extern int _PyModule_IsExtension(PyObject *obj);
|
||||||
|
|
||||||
|
typedef int (*_Py_modexecfunc)(PyObject *);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *md_dict;
|
PyObject *md_dict;
|
||||||
PyModuleDef *md_def;
|
|
||||||
void *md_state;
|
void *md_state;
|
||||||
PyObject *md_weaklist;
|
PyObject *md_weaklist;
|
||||||
// for logging purposes after md_dict is cleared
|
// for logging purposes after md_dict is cleared
|
||||||
PyObject *md_name;
|
PyObject *md_name;
|
||||||
|
bool md_token_is_def; /* if true, `md_token` is the PyModuleDef */
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
void *md_gil;
|
void *md_gil;
|
||||||
#endif
|
#endif
|
||||||
|
Py_ssize_t md_state_size;
|
||||||
|
traverseproc md_state_traverse;
|
||||||
|
inquiry md_state_clear;
|
||||||
|
freefunc md_state_free;
|
||||||
|
void *md_token;
|
||||||
|
_Py_modexecfunc md_exec; /* only set if md_token_is_def is true */
|
||||||
} PyModuleObject;
|
} PyModuleObject;
|
||||||
|
|
||||||
static inline PyModuleDef* _PyModule_GetDef(PyObject *mod) {
|
#define _PyModule_CAST(op) \
|
||||||
assert(PyModule_Check(mod));
|
(assert(PyModule_Check(op)), _Py_CAST(PyModuleObject*, (op)))
|
||||||
return ((PyModuleObject *)mod)->md_def;
|
|
||||||
|
static inline PyModuleDef *_PyModule_GetDefOrNull(PyObject *arg) {
|
||||||
|
PyModuleObject *mod = _PyModule_CAST(arg);
|
||||||
|
if (mod->md_token_is_def) {
|
||||||
|
return (PyModuleDef *)mod->md_token;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline PyModuleDef *_PyModule_GetToken(PyObject *arg) {
|
||||||
|
PyModuleObject *mod = _PyModule_CAST(arg);
|
||||||
|
return mod->md_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void* _PyModule_GetState(PyObject* mod) {
|
static inline void* _PyModule_GetState(PyObject* mod) {
|
||||||
assert(PyModule_Check(mod));
|
return _PyModule_CAST(mod)->md_state;
|
||||||
return ((PyModuleObject *)mod)->md_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline PyObject* _PyModule_GetDict(PyObject *mod) {
|
static inline PyObject* _PyModule_GetDict(PyObject *mod) {
|
||||||
assert(PyModule_Check(mod));
|
PyObject *dict = _PyModule_CAST(mod)->md_dict;
|
||||||
PyObject *dict = ((PyModuleObject *)mod) -> md_dict;
|
|
||||||
// _PyModule_GetDict(mod) must not be used after calling module_clear(mod)
|
// _PyModule_GetDict(mod) must not be used after calling module_clear(mod)
|
||||||
assert(dict != NULL);
|
assert(dict != NULL);
|
||||||
return dict; // borrowed reference
|
return dict; // borrowed reference
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,19 @@ struct PyModuleDef_Slot {
|
||||||
#endif
|
#endif
|
||||||
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
|
||||||
# define Py_mod_abi 5
|
# define Py_mod_abi 5
|
||||||
|
# define Py_mod_name 6
|
||||||
|
# define Py_mod_doc 7
|
||||||
|
# define Py_mod_state_size 8
|
||||||
|
# define Py_mod_methods 9
|
||||||
|
# define Py_mod_state_traverse 10
|
||||||
|
# define Py_mod_state_clear 11
|
||||||
|
# define Py_mod_state_free 12
|
||||||
|
# define Py_mod_token 13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
#define _Py_mod_LAST_SLOT 5
|
#define _Py_mod_LAST_SLOT 13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* New in 3.5 */
|
#endif /* New in 3.5 */
|
||||||
|
|
@ -109,6 +117,13 @@ struct PyModuleDef_Slot {
|
||||||
PyAPI_FUNC(int) PyUnstable_Module_SetGIL(PyObject *module, void *gil);
|
PyAPI_FUNC(int) PyUnstable_Module_SetGIL(PyObject *module, void *gil);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
|
||||||
|
PyAPI_FUNC(PyObject *) PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *,
|
||||||
|
PyObject *spec);
|
||||||
|
PyAPI_FUNC(int) PyModule_Exec(PyObject *mod);
|
||||||
|
PyAPI_FUNC(int) PyModule_GetStateSize(PyObject *mod, Py_ssize_t *result);
|
||||||
|
PyAPI_FUNC(int) PyModule_GetToken(PyObject *, void **result);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _Py_OPAQUE_PYOBJECT
|
#ifndef _Py_OPAQUE_PYOBJECT
|
||||||
struct PyModuleDef {
|
struct PyModuleDef {
|
||||||
|
|
|
||||||
|
|
@ -839,6 +839,11 @@ PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *);
|
||||||
PyAPI_FUNC(int) PyType_Freeze(PyTypeObject *type);
|
PyAPI_FUNC(int) PyType_Freeze(PyTypeObject *type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
|
||||||
|
PyAPI_FUNC(PyObject *) PyType_GetModuleByToken(PyTypeObject *type,
|
||||||
|
const void *token);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
185
Lib/test/test_capi/test_module.py
Normal file
185
Lib/test/test_capi/test_module.py
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
# The C functions used by this module are in:
|
||||||
|
# Modules/_testcapi/module.c
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import types
|
||||||
|
from test.support import import_helper, subTests
|
||||||
|
|
||||||
|
# Skip this test if the _testcapi module isn't available.
|
||||||
|
_testcapi = import_helper.import_module('_testcapi')
|
||||||
|
|
||||||
|
|
||||||
|
class FakeSpec:
|
||||||
|
name = 'testmod'
|
||||||
|
|
||||||
|
DEF_SLOTS = (
|
||||||
|
'Py_mod_name', 'Py_mod_doc', 'Py_mod_state_size', 'Py_mod_methods',
|
||||||
|
'Py_mod_state_traverse', 'Py_mod_state_clear', 'Py_mod_state_free',
|
||||||
|
'Py_mod_token',
|
||||||
|
)
|
||||||
|
|
||||||
|
def def_and_token(mod):
|
||||||
|
return (
|
||||||
|
_testcapi.pymodule_get_def(mod),
|
||||||
|
_testcapi.pymodule_get_token(mod),
|
||||||
|
)
|
||||||
|
|
||||||
|
class TestModFromSlotsAndSpec(unittest.TestCase):
|
||||||
|
def test_empty(self):
|
||||||
|
mod = _testcapi.module_from_slots_empty(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
size = _testcapi.pymodule_get_state_size(mod)
|
||||||
|
self.assertEqual(size, 0)
|
||||||
|
|
||||||
|
def test_null_slots(self):
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
_testcapi.module_from_slots_null(FakeSpec())
|
||||||
|
|
||||||
|
def test_none_spec(self):
|
||||||
|
# The spec currently must contain a name
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
_testcapi.module_from_slots_empty(None)
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
_testcapi.module_from_slots_name(None)
|
||||||
|
|
||||||
|
def test_name(self):
|
||||||
|
# Py_mod_name (and PyModuleDef.m_name) are currently ignored when
|
||||||
|
# spec is given.
|
||||||
|
# We still test that it's accepted.
|
||||||
|
mod = _testcapi.module_from_slots_name(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, None)
|
||||||
|
|
||||||
|
def test_doc(self):
|
||||||
|
mod = _testcapi.module_from_slots_doc(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, 'the docstring')
|
||||||
|
|
||||||
|
def test_size(self):
|
||||||
|
mod = _testcapi.module_from_slots_size(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, None)
|
||||||
|
size = _testcapi.pymodule_get_state_size(mod)
|
||||||
|
self.assertEqual(size, 123)
|
||||||
|
|
||||||
|
def test_methods(self):
|
||||||
|
mod = _testcapi.module_from_slots_methods(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, None)
|
||||||
|
self.assertEqual(mod.a_method(456), (mod, 456))
|
||||||
|
|
||||||
|
def test_gc(self):
|
||||||
|
mod = _testcapi.module_from_slots_gc(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, None)
|
||||||
|
|
||||||
|
# Check that the requested hook functions (which module_from_slots_gc
|
||||||
|
# stores as attributes) match what's in the module (as retrieved by
|
||||||
|
# _testinternalcapi.module_get_gc_hooks)
|
||||||
|
_testinternalcapi = import_helper.import_module('_testinternalcapi')
|
||||||
|
traverse, clear, free = _testinternalcapi.module_get_gc_hooks(mod)
|
||||||
|
self.assertEqual(traverse, mod.traverse)
|
||||||
|
self.assertEqual(clear, mod.clear)
|
||||||
|
self.assertEqual(free, mod.free)
|
||||||
|
|
||||||
|
def test_token(self):
|
||||||
|
mod = _testcapi.module_from_slots_token(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, _testcapi.module_test_token))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, None)
|
||||||
|
|
||||||
|
def test_exec(self):
|
||||||
|
mod = _testcapi.module_from_slots_exec(FakeSpec())
|
||||||
|
self.assertIsInstance(mod, types.ModuleType)
|
||||||
|
self.assertEqual(def_and_token(mod), (0, 0))
|
||||||
|
self.assertEqual(mod.__name__, 'testmod')
|
||||||
|
self.assertEqual(mod.__doc__, None)
|
||||||
|
self.assertEqual(mod.a_number, 456)
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
spec = FakeSpec()
|
||||||
|
spec._gimme_this = "not a module object"
|
||||||
|
mod = _testcapi.module_from_slots_create(spec)
|
||||||
|
self.assertIsInstance(mod, str)
|
||||||
|
self.assertEqual(mod, "not a module object")
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
_testcapi.pymodule_get_def(mod),
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
_testcapi.pymodule_get_token(mod)
|
||||||
|
|
||||||
|
def test_def_slot(self):
|
||||||
|
"""Slots that replace PyModuleDef fields can't be used with PyModuleDef
|
||||||
|
"""
|
||||||
|
for name in DEF_SLOTS:
|
||||||
|
with self.subTest(name):
|
||||||
|
spec = FakeSpec()
|
||||||
|
spec._test_slot_id = getattr(_testcapi, name)
|
||||||
|
with self.assertRaises(SystemError) as cm:
|
||||||
|
_testcapi.module_from_def_slot(spec)
|
||||||
|
self.assertIn(name, str(cm.exception))
|
||||||
|
self.assertIn("PyModuleDef", str(cm.exception))
|
||||||
|
|
||||||
|
def test_repeated_def_slot(self):
|
||||||
|
"""Slots that replace PyModuleDef fields can't be repeated"""
|
||||||
|
for name in (*DEF_SLOTS, 'Py_mod_exec'):
|
||||||
|
with self.subTest(name):
|
||||||
|
spec = FakeSpec()
|
||||||
|
spec._test_slot_id = getattr(_testcapi, name)
|
||||||
|
with self.assertRaises(SystemError) as cm:
|
||||||
|
_testcapi.module_from_slots_repeat_slot(spec)
|
||||||
|
self.assertIn(name, str(cm.exception))
|
||||||
|
self.assertIn("more than one", str(cm.exception))
|
||||||
|
|
||||||
|
def test_null_def_slot(self):
|
||||||
|
"""Slots that replace PyModuleDef fields can't be NULL"""
|
||||||
|
for name in (*DEF_SLOTS, 'Py_mod_exec'):
|
||||||
|
with self.subTest(name):
|
||||||
|
spec = FakeSpec()
|
||||||
|
spec._test_slot_id = getattr(_testcapi, name)
|
||||||
|
with self.assertRaises(SystemError) as cm:
|
||||||
|
_testcapi.module_from_slots_null_slot(spec)
|
||||||
|
self.assertIn(name, str(cm.exception))
|
||||||
|
self.assertIn("NULL", str(cm.exception))
|
||||||
|
|
||||||
|
def test_def_multiple_exec(self):
|
||||||
|
"""PyModule_Exec runs all exec slots of PyModuleDef-defined module"""
|
||||||
|
mod = _testcapi.module_from_def_multiple_exec(FakeSpec())
|
||||||
|
self.assertFalse(hasattr(mod, 'a_number'))
|
||||||
|
_testcapi.pymodule_exec(mod)
|
||||||
|
self.assertEqual(mod.a_number, 456)
|
||||||
|
self.assertEqual(mod.another_number, 789)
|
||||||
|
_testcapi.pymodule_exec(mod)
|
||||||
|
self.assertEqual(mod.a_number, 456)
|
||||||
|
self.assertEqual(mod.another_number, -789)
|
||||||
|
def_ptr, token = def_and_token(mod)
|
||||||
|
self.assertEqual(def_ptr, token)
|
||||||
|
|
||||||
|
def test_def_token(self):
|
||||||
|
"""In PyModuleDef-defined modules, the def is the token"""
|
||||||
|
mod = _testcapi.module_from_def_multiple_exec(FakeSpec())
|
||||||
|
def_ptr, token = def_and_token(mod)
|
||||||
|
self.assertEqual(def_ptr, token)
|
||||||
|
self.assertGreater(def_ptr, 0)
|
||||||
|
|
||||||
|
@subTests('name, expected_size', [
|
||||||
|
(__name__, 0), # Python module
|
||||||
|
('_testsinglephase', -1), # single-phase init
|
||||||
|
('sys', -1),
|
||||||
|
])
|
||||||
|
def test_get_state_size(self, name, expected_size):
|
||||||
|
mod = import_helper.import_module(name)
|
||||||
|
size = _testcapi.pymodule_get_state_size(mod)
|
||||||
|
self.assertEqual(size, expected_size)
|
||||||
|
|
@ -195,6 +195,24 @@ class H2(int): pass
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
_testcapi.pytype_getmodulebydef(H2)
|
_testcapi.pytype_getmodulebydef(H2)
|
||||||
|
|
||||||
|
def test_get_module_by_token(self):
|
||||||
|
token = _testcapi.pymodule_get_token(_testcapi)
|
||||||
|
|
||||||
|
heaptype = _testcapi.create_type_with_token('_testcapi.H', 0)
|
||||||
|
mod = _testcapi.pytype_getmodulebytoken(heaptype, token)
|
||||||
|
self.assertIs(mod, _testcapi)
|
||||||
|
|
||||||
|
class H1(heaptype): pass
|
||||||
|
mod = _testcapi.pytype_getmodulebytoken(H1, token)
|
||||||
|
self.assertIs(mod, _testcapi)
|
||||||
|
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
_testcapi.pytype_getmodulebytoken(int, token)
|
||||||
|
|
||||||
|
class H2(int): pass
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
_testcapi.pytype_getmodulebytoken(H2, token)
|
||||||
|
|
||||||
def test_freeze(self):
|
def test_freeze(self):
|
||||||
# test PyType_Freeze()
|
# test PyType_Freeze()
|
||||||
type_freeze = _testcapi.type_freeze
|
type_freeze = _testcapi.type_freeze
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
SOURCES = [
|
SOURCES = [
|
||||||
os.path.join(os.path.dirname(__file__), 'extension.c'),
|
os.path.join(os.path.dirname(__file__), 'extension.c'),
|
||||||
os.path.join(os.path.dirname(__file__), 'create_moduledef.c'),
|
|
||||||
]
|
]
|
||||||
SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
|
SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// Workaround for testing _Py_OPAQUE_PYOBJECT.
|
|
||||||
// See end of 'extension.c'
|
|
||||||
|
|
||||||
|
|
||||||
#undef _Py_OPAQUE_PYOBJECT
|
|
||||||
#undef Py_LIMITED_API
|
|
||||||
#include "Python.h"
|
|
||||||
|
|
||||||
|
|
||||||
// (repeated definition to avoid creating a header)
|
|
||||||
extern PyObject *testcext_create_moduledef(
|
|
||||||
const char *name, const char *doc,
|
|
||||||
PyMethodDef *methods, PyModuleDef_Slot *slots);
|
|
||||||
|
|
||||||
PyObject *testcext_create_moduledef(
|
|
||||||
const char *name, const char *doc,
|
|
||||||
PyMethodDef *methods, PyModuleDef_Slot *slots) {
|
|
||||||
|
|
||||||
static struct PyModuleDef _testcext_module = {
|
|
||||||
PyModuleDef_HEAD_INIT,
|
|
||||||
};
|
|
||||||
if (!_testcext_module.m_name) {
|
|
||||||
_testcext_module.m_name = name;
|
|
||||||
_testcext_module.m_doc = doc;
|
|
||||||
_testcext_module.m_methods = methods;
|
|
||||||
_testcext_module.m_slots = slots;
|
|
||||||
}
|
|
||||||
return PyModuleDef_Init(&_testcext_module);
|
|
||||||
}
|
|
||||||
|
|
@ -78,7 +78,7 @@ _testcext_exec(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _FUNC_NAME(NAME) PyInit_ ## NAME
|
#define _FUNC_NAME(NAME) PyModExport_ ## NAME
|
||||||
#define FUNC_NAME(NAME) _FUNC_NAME(NAME)
|
#define FUNC_NAME(NAME) _FUNC_NAME(NAME)
|
||||||
|
|
||||||
// Converting from function pointer to void* has undefined behavior, but
|
// Converting from function pointer to void* has undefined behavior, but
|
||||||
|
|
@ -88,58 +88,40 @@ _testcext_exec(
|
||||||
_Py_COMP_DIAG_PUSH
|
_Py_COMP_DIAG_PUSH
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||||
#elif defined(__clang__)
|
#elif defined(__clang__)
|
||||||
#pragma clang diagnostic ignored "-Wpedantic"
|
#pragma clang diagnostic ignored "-Wpedantic"
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-qual"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
PyDoc_STRVAR(_testcext_doc, "C test extension.");
|
||||||
|
|
||||||
static PyModuleDef_Slot _testcext_slots[] = {
|
static PyModuleDef_Slot _testcext_slots[] = {
|
||||||
|
{Py_mod_name, STR(MODULE_NAME)},
|
||||||
|
{Py_mod_doc, (void*)(char*)_testcext_doc},
|
||||||
{Py_mod_exec, (void*)_testcext_exec},
|
{Py_mod_exec, (void*)_testcext_exec},
|
||||||
|
{Py_mod_methods, _testcext_methods},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
_Py_COMP_DIAG_POP
|
_Py_COMP_DIAG_POP
|
||||||
|
|
||||||
PyDoc_STRVAR(_testcext_doc, "C test extension.");
|
PyMODEXPORT_FUNC
|
||||||
|
|
||||||
#ifndef _Py_OPAQUE_PYOBJECT
|
|
||||||
|
|
||||||
static struct PyModuleDef _testcext_module = {
|
|
||||||
PyModuleDef_HEAD_INIT, // m_base
|
|
||||||
STR(MODULE_NAME), // m_name
|
|
||||||
_testcext_doc, // m_doc
|
|
||||||
0, // m_size
|
|
||||||
_testcext_methods, // m_methods
|
|
||||||
_testcext_slots, // m_slots
|
|
||||||
NULL, // m_traverse
|
|
||||||
NULL, // m_clear
|
|
||||||
NULL, // m_free
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
|
||||||
FUNC_NAME(MODULE_NAME)(void)
|
FUNC_NAME(MODULE_NAME)(void)
|
||||||
{
|
{
|
||||||
return PyModuleDef_Init(&_testcext_module);
|
return _testcext_slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // _Py_OPAQUE_PYOBJECT
|
// Also define the soft-deprecated entrypoint to ensure it isn't called
|
||||||
|
|
||||||
// Opaque PyObject means that PyModuleDef is also opaque and cannot be
|
|
||||||
// declared statically. See PEP 793.
|
|
||||||
// So, this part of module creation is split into a separate source file
|
|
||||||
// which uses non-limited API.
|
|
||||||
|
|
||||||
// (repeated definition to avoid creating a header)
|
|
||||||
extern PyObject *testcext_create_moduledef(
|
|
||||||
const char *name, const char *doc,
|
|
||||||
PyMethodDef *methods, PyModuleDef_Slot *slots);
|
|
||||||
|
|
||||||
|
#define _INITFUNC_NAME(NAME) PyInit_ ## NAME
|
||||||
|
#define INITFUNC_NAME(NAME) _INITFUNC_NAME(NAME)
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
FUNC_NAME(MODULE_NAME)(void)
|
INITFUNC_NAME(MODULE_NAME)(void)
|
||||||
{
|
{
|
||||||
return testcext_create_moduledef(
|
PyErr_SetString(
|
||||||
STR(MODULE_NAME), _testcext_doc, _testcext_methods, _testcext_slots);
|
PyExc_AssertionError,
|
||||||
|
"PyInit_* function called while a PyModExport_* one is available");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _Py_OPAQUE_PYOBJECT
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,6 @@ def main():
|
||||||
# Define _Py_OPAQUE_PYOBJECT macro
|
# Define _Py_OPAQUE_PYOBJECT macro
|
||||||
if opaque_pyobject:
|
if opaque_pyobject:
|
||||||
cflags.append(f'-D_Py_OPAQUE_PYOBJECT')
|
cflags.append(f'-D_Py_OPAQUE_PYOBJECT')
|
||||||
sources.append('create_moduledef.c')
|
|
||||||
|
|
||||||
if internal:
|
if internal:
|
||||||
cflags.append('-DTEST_INTERNAL_C_API=1')
|
cflags.append('-DTEST_INTERNAL_C_API=1')
|
||||||
|
|
|
||||||
|
|
@ -2497,6 +2497,21 @@ def test_multi_init_extension_per_interpreter_gil_compat(self):
|
||||||
self.check_compatible_here(
|
self.check_compatible_here(
|
||||||
modname, filename, strict=False, isolated=False)
|
modname, filename, strict=False, isolated=False)
|
||||||
|
|
||||||
|
@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
|
||||||
|
def test_testmultiphase_exec_multiple(self):
|
||||||
|
modname = '_testmultiphase_exec_multiple'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
module = import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
# All three exec's were called.
|
||||||
|
self.assertEqual(module.a, 1)
|
||||||
|
self.assertEqual(module.b, 2)
|
||||||
|
self.assertEqual(module.c, 3)
|
||||||
|
# They were called in order.
|
||||||
|
keys = list(module.__dict__)
|
||||||
|
self.assertLess(keys.index('a'), keys.index('b'))
|
||||||
|
self.assertLess(keys.index('b'), keys.index('c'))
|
||||||
|
|
||||||
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
|
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
|
||||||
def test_python_compat(self):
|
def test_python_compat(self):
|
||||||
module = 'threading'
|
module = 'threading'
|
||||||
|
|
@ -3394,6 +3409,83 @@ def test_basic_multiple_interpreters_reset_each(self):
|
||||||
# * module's global state was initialized, not reset
|
# * module's global state was initialized, not reset
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
|
||||||
|
class ModexportTests(unittest.TestCase):
|
||||||
|
def test_from_modexport(self):
|
||||||
|
modname = '_test_from_modexport'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
module = import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
|
||||||
|
self.assertEqual(module.__name__, modname)
|
||||||
|
|
||||||
|
def test_from_modexport_null(self):
|
||||||
|
modname = '_test_from_modexport_null'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
with self.assertRaises(SystemError):
|
||||||
|
import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
|
||||||
|
def test_from_modexport_exception(self):
|
||||||
|
modname = '_test_from_modexport_exception'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
|
||||||
|
def test_from_modexport_create_nonmodule(self):
|
||||||
|
modname = '_test_from_modexport_create_nonmodule'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
module = import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
self.assertIsInstance(module, str)
|
||||||
|
|
||||||
|
def test_from_modexport_smoke(self):
|
||||||
|
# General positive test for sundry features
|
||||||
|
# (PyModule_FromSlotsAndSpec tests exercise these more carefully)
|
||||||
|
modname = '_test_from_modexport_smoke'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
module = import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
self.assertEqual(module.__doc__, "the expected docstring")
|
||||||
|
self.assertEqual(module.number, 147)
|
||||||
|
self.assertEqual(module.get_state_int(), 258)
|
||||||
|
self.assertGreater(module.get_test_token(), 0)
|
||||||
|
|
||||||
|
def test_from_modexport_smoke_token(self):
|
||||||
|
_testcapi = import_module("_testcapi")
|
||||||
|
|
||||||
|
modname = '_test_from_modexport_smoke'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
module = import_extension_from_file(modname, filename,
|
||||||
|
put_in_sys_modules=False)
|
||||||
|
token = module.get_test_token()
|
||||||
|
self.assertEqual(_testcapi.pymodule_get_token(module), token)
|
||||||
|
|
||||||
|
tp = module.Example
|
||||||
|
self.assertEqual(_testcapi.pytype_getmodulebytoken(tp, token), module)
|
||||||
|
class Sub(tp):
|
||||||
|
pass
|
||||||
|
self.assertEqual(_testcapi.pytype_getmodulebytoken(Sub, token), module)
|
||||||
|
|
||||||
|
def test_from_modexport_empty_slots(self):
|
||||||
|
# Module to test that:
|
||||||
|
# - no slots are mandatory for PyModExport
|
||||||
|
# - the slots array is used as the default token
|
||||||
|
modname = '_test_from_modexport_empty_slots'
|
||||||
|
filename = _testmultiphase.__file__
|
||||||
|
module = import_extension_from_file(
|
||||||
|
modname, filename, put_in_sys_modules=False)
|
||||||
|
|
||||||
|
self.assertEqual(module.__name__, modname)
|
||||||
|
self.assertEqual(module.__doc__, None)
|
||||||
|
|
||||||
|
_testcapi = import_module("_testcapi")
|
||||||
|
smoke_mod = import_extension_from_file(
|
||||||
|
'_test_from_modexport_smoke', filename, put_in_sys_modules=False)
|
||||||
|
self.assertEqual(_testcapi.pymodule_get_token(module),
|
||||||
|
smoke_mod.get_modexport_empty_slots())
|
||||||
|
|
||||||
@cpython_only
|
@cpython_only
|
||||||
class TestMagicNumber(unittest.TestCase):
|
class TestMagicNumber(unittest.TestCase):
|
||||||
def test_magic_number_endianness(self):
|
def test_magic_number_endianness(self):
|
||||||
|
|
|
||||||
5
Lib/test/test_stable_abi_ctypes.py
generated
5
Lib/test/test_stable_abi_ctypes.py
generated
|
|
@ -469,8 +469,10 @@ SYMBOL_NAMES = (
|
||||||
"PyModule_AddStringConstant",
|
"PyModule_AddStringConstant",
|
||||||
"PyModule_AddType",
|
"PyModule_AddType",
|
||||||
"PyModule_Create2",
|
"PyModule_Create2",
|
||||||
|
"PyModule_Exec",
|
||||||
"PyModule_ExecDef",
|
"PyModule_ExecDef",
|
||||||
"PyModule_FromDefAndSpec2",
|
"PyModule_FromDefAndSpec2",
|
||||||
|
"PyModule_FromSlotsAndSpec",
|
||||||
"PyModule_GetDef",
|
"PyModule_GetDef",
|
||||||
"PyModule_GetDict",
|
"PyModule_GetDict",
|
||||||
"PyModule_GetFilename",
|
"PyModule_GetFilename",
|
||||||
|
|
@ -478,6 +480,8 @@ SYMBOL_NAMES = (
|
||||||
"PyModule_GetName",
|
"PyModule_GetName",
|
||||||
"PyModule_GetNameObject",
|
"PyModule_GetNameObject",
|
||||||
"PyModule_GetState",
|
"PyModule_GetState",
|
||||||
|
"PyModule_GetStateSize",
|
||||||
|
"PyModule_GetToken",
|
||||||
"PyModule_New",
|
"PyModule_New",
|
||||||
"PyModule_NewObject",
|
"PyModule_NewObject",
|
||||||
"PyModule_SetDocString",
|
"PyModule_SetDocString",
|
||||||
|
|
@ -733,6 +737,7 @@ SYMBOL_NAMES = (
|
||||||
"PyType_GetFullyQualifiedName",
|
"PyType_GetFullyQualifiedName",
|
||||||
"PyType_GetModule",
|
"PyType_GetModule",
|
||||||
"PyType_GetModuleByDef",
|
"PyType_GetModuleByDef",
|
||||||
|
"PyType_GetModuleByToken",
|
||||||
"PyType_GetModuleName",
|
"PyType_GetModuleName",
|
||||||
"PyType_GetModuleState",
|
"PyType_GetModuleState",
|
||||||
"PyType_GetName",
|
"PyType_GetName",
|
||||||
|
|
|
||||||
|
|
@ -1725,9 +1725,10 @@ def get_gen(): yield 1
|
||||||
check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit)
|
check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit)
|
||||||
# module
|
# module
|
||||||
if support.Py_GIL_DISABLED:
|
if support.Py_GIL_DISABLED:
|
||||||
check(unittest, size('PPPPPP'))
|
md_gil = 'P'
|
||||||
else:
|
else:
|
||||||
check(unittest, size('PPPPP'))
|
md_gil = ''
|
||||||
|
check(unittest, size('PPPP?' + md_gil + 'NPPPPP'))
|
||||||
# None
|
# None
|
||||||
check(None, size(''))
|
check(None, size(''))
|
||||||
# NotImplementedType
|
# NotImplementedType
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
:pep:`793`: Add a new entry point for C extension modules,
|
||||||
|
``PyModExport_<modulename>``.
|
||||||
|
|
@ -2611,3 +2611,31 @@
|
||||||
added = '3.15'
|
added = '3.15'
|
||||||
[const.PyABIInfo_FREETHREADING_AGNOSTIC]
|
[const.PyABIInfo_FREETHREADING_AGNOSTIC]
|
||||||
added = '3.15'
|
added = '3.15'
|
||||||
|
[function.PyModule_FromSlotsAndSpec]
|
||||||
|
added = '3.15'
|
||||||
|
[function.PyModule_Exec]
|
||||||
|
added = '3.15'
|
||||||
|
[function.PyModule_GetToken]
|
||||||
|
added = '3.15'
|
||||||
|
[function.PyType_GetModuleByToken]
|
||||||
|
added = '3.15'
|
||||||
|
[function.PyModule_GetStateSize]
|
||||||
|
added = '3.15'
|
||||||
|
[macro.PyMODEXPORT_FUNC]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_name]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_doc]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_state_size]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_methods]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_state_traverse]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_state_clear]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_state_free]
|
||||||
|
added = '3.15'
|
||||||
|
[const.Py_mod_token]
|
||||||
|
added = '3.15'
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@
|
||||||
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
||||||
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
||||||
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c
|
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c
|
||||||
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c
|
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c
|
||||||
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
|
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
|
||||||
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
||||||
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
||||||
|
|
|
||||||
|
|
@ -528,6 +528,21 @@ pytype_getmodulebydef(PyObject *self, PyObject *type)
|
||||||
return Py_XNewRef(mod);
|
return Py_XNewRef(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pytype_getmodulebytoken(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *type;
|
||||||
|
PyObject *py_token;
|
||||||
|
if (!PyArg_ParseTuple(args, "OO", &type, &py_token)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *token = PyLong_AsVoidPtr(py_token);
|
||||||
|
if ((!token) && PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyType_GetModuleByToken((PyTypeObject *)type, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef TestMethods[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"pytype_fromspec_meta", pytype_fromspec_meta, METH_O},
|
{"pytype_fromspec_meta", pytype_fromspec_meta, METH_O},
|
||||||
|
|
@ -546,6 +561,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"get_tp_token", get_tp_token, METH_O},
|
{"get_tp_token", get_tp_token, METH_O},
|
||||||
{"pytype_getbasebytoken", pytype_getbasebytoken, METH_VARARGS},
|
{"pytype_getbasebytoken", pytype_getbasebytoken, METH_VARARGS},
|
||||||
{"pytype_getmodulebydef", pytype_getmodulebydef, METH_O},
|
{"pytype_getmodulebydef", pytype_getmodulebydef, METH_O},
|
||||||
|
{"pytype_getmodulebytoken", pytype_getmodulebytoken, METH_VARARGS},
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
378
Modules/_testcapi/module.c
Normal file
378
Modules/_testcapi/module.c
Normal file
|
|
@ -0,0 +1,378 @@
|
||||||
|
#include "parts.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
// Test PyModule_* API
|
||||||
|
|
||||||
|
/* unittest Cases that use these functions are in:
|
||||||
|
* Lib/test/test_capi/test_module.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_empty(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_null(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
return PyModule_FromSlotsAndSpec(NULL, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_name(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_name, "currently ignored..."},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_doc(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_doc, "the docstring"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_size(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_state_size, (void*)123},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
if (!mod) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
a_method(PyObject *self, PyObject *arg)
|
||||||
|
{
|
||||||
|
return PyTuple_Pack(2, self, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef a_methoddef_array[] = {
|
||||||
|
{"a_method", a_method, METH_O},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_methods(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_methods, a_methoddef_array},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int noop_traverse(PyObject *self, visitproc visit, void *arg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int noop_clear(PyObject *self) { return 0; }
|
||||||
|
static void noop_free(void *self) { }
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_gc(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_state_traverse, noop_traverse},
|
||||||
|
{Py_mod_state_clear, noop_clear},
|
||||||
|
{Py_mod_state_free, noop_free},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
if (!mod) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (PyModule_Add(mod, "traverse", PyLong_FromVoidPtr(&noop_traverse)) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (PyModule_Add(mod, "clear", PyLong_FromVoidPtr(&noop_clear)) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (PyModule_Add(mod, "free", PyLong_FromVoidPtr(&noop_free)) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char test_token;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_token(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_token, (void*)&test_token},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
if (!mod) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *got_token;
|
||||||
|
if (PyModule_GetToken(mod, &got_token) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
assert(got_token == &test_token);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
simple_exec(PyObject *module)
|
||||||
|
{
|
||||||
|
return PyModule_AddIntConstant(module, "a_number", 456);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_exec(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_exec, simple_exec},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
if (!mod) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int res = PyObject_HasAttrStringWithError(mod, "a_number");
|
||||||
|
if (res < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
assert(res == 0);
|
||||||
|
if (PyModule_Exec(mod) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
create_attr_from_spec(PyObject *spec, PyObject *def)
|
||||||
|
{
|
||||||
|
assert(!def);
|
||||||
|
return PyObject_GetAttrString(spec, "_gimme_this");
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_create(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_create, create_attr_from_spec},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
slot_from_object(PyObject *obj)
|
||||||
|
{
|
||||||
|
PyObject *slot_id_obj = PyObject_GetAttrString(obj, "_test_slot_id");
|
||||||
|
if (slot_id_obj == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int slot_id = PyLong_AsInt(slot_id_obj);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return slot_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_repeat_slot(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
int slot_id = slot_from_object(spec);
|
||||||
|
if (slot_id < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{slot_id, "anything"},
|
||||||
|
{slot_id, "anything else"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_slots_null_slot(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
int slot_id = slot_from_object(spec);
|
||||||
|
if (slot_id < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{slot_id, NULL},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_def_slot(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
int slot_id = slot_from_object(spec);
|
||||||
|
if (slot_id < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyModuleDef_Slot slots[] = {
|
||||||
|
{slot_id, "anything"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
PyModuleDef def = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
.m_name = "currently ignored",
|
||||||
|
.m_slots = slots,
|
||||||
|
};
|
||||||
|
// PyModuleDef is normally static; the real requirement is that it
|
||||||
|
// must outlive its module.
|
||||||
|
// Here, module creation fails, so it's fine on the stack.
|
||||||
|
PyObject *result = PyModule_FromDefAndSpec(&def, spec);
|
||||||
|
assert(result == NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
another_exec(PyObject *module)
|
||||||
|
{
|
||||||
|
/* Make sure simple_exec was called */
|
||||||
|
assert(PyObject_HasAttrString(module, "a_number"));
|
||||||
|
|
||||||
|
/* Add or negate a global called 'another_number' */
|
||||||
|
PyObject *another_number;
|
||||||
|
if (PyObject_GetOptionalAttrString(module, "another_number",
|
||||||
|
&another_number) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!another_number) {
|
||||||
|
return PyModule_AddIntConstant(module, "another_number", 789);
|
||||||
|
}
|
||||||
|
PyObject *neg_number = PyNumber_Negative(another_number);
|
||||||
|
Py_DECREF(another_number);
|
||||||
|
if (!neg_number) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int result = PyObject_SetAttrString(module, "another_number",
|
||||||
|
neg_number);
|
||||||
|
Py_DECREF(neg_number);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_from_def_multiple_exec(PyObject *self, PyObject *spec)
|
||||||
|
{
|
||||||
|
static PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_exec, simple_exec},
|
||||||
|
{Py_mod_exec, another_exec},
|
||||||
|
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
static PyModuleDef def = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
.m_name = "currently ignored",
|
||||||
|
.m_slots = slots,
|
||||||
|
};
|
||||||
|
return PyModule_FromDefAndSpec(&def, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pymodule_exec(PyObject *self, PyObject *module)
|
||||||
|
{
|
||||||
|
if (PyModule_Exec(module) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pymodule_get_token(PyObject *self, PyObject *module)
|
||||||
|
{
|
||||||
|
void *token;
|
||||||
|
if (PyModule_GetToken(module, &token) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyLong_FromVoidPtr(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pymodule_get_def(PyObject *self, PyObject *module)
|
||||||
|
{
|
||||||
|
PyModuleDef *def = PyModule_GetDef(module);
|
||||||
|
if (!def && PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyLong_FromVoidPtr(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pymodule_get_state_size(PyObject *self, PyObject *module)
|
||||||
|
{
|
||||||
|
Py_ssize_t size;
|
||||||
|
if (PyModule_GetStateSize(module, &size) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyLong_FromSsize_t(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef test_methods[] = {
|
||||||
|
{"module_from_slots_empty", module_from_slots_empty, METH_O},
|
||||||
|
{"module_from_slots_null", module_from_slots_null, METH_O},
|
||||||
|
{"module_from_slots_name", module_from_slots_name, METH_O},
|
||||||
|
{"module_from_slots_doc", module_from_slots_doc, METH_O},
|
||||||
|
{"module_from_slots_size", module_from_slots_size, METH_O},
|
||||||
|
{"module_from_slots_methods", module_from_slots_methods, METH_O},
|
||||||
|
{"module_from_slots_gc", module_from_slots_gc, METH_O},
|
||||||
|
{"module_from_slots_token", module_from_slots_token, METH_O},
|
||||||
|
{"module_from_slots_exec", module_from_slots_exec, METH_O},
|
||||||
|
{"module_from_slots_create", module_from_slots_create, METH_O},
|
||||||
|
{"module_from_slots_repeat_slot", module_from_slots_repeat_slot, METH_O},
|
||||||
|
{"module_from_slots_null_slot", module_from_slots_null_slot, METH_O},
|
||||||
|
{"module_from_def_multiple_exec", module_from_def_multiple_exec, METH_O},
|
||||||
|
{"module_from_def_slot", module_from_def_slot, METH_O},
|
||||||
|
{"pymodule_get_token", pymodule_get_token, METH_O},
|
||||||
|
{"pymodule_get_def", pymodule_get_def, METH_O},
|
||||||
|
{"pymodule_get_state_size", pymodule_get_state_size, METH_O},
|
||||||
|
{"pymodule_exec", pymodule_exec, METH_O},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyTestCapi_Init_Module(PyObject *m)
|
||||||
|
{
|
||||||
|
#define ADD_INT_MACRO(C) if (PyModule_AddIntConstant(m, #C, C) < 0) return -1;
|
||||||
|
ADD_INT_MACRO(Py_mod_create);
|
||||||
|
ADD_INT_MACRO(Py_mod_exec);
|
||||||
|
ADD_INT_MACRO(Py_mod_multiple_interpreters);
|
||||||
|
ADD_INT_MACRO(Py_mod_gil);
|
||||||
|
ADD_INT_MACRO(Py_mod_name);
|
||||||
|
ADD_INT_MACRO(Py_mod_doc);
|
||||||
|
ADD_INT_MACRO(Py_mod_state_size);
|
||||||
|
ADD_INT_MACRO(Py_mod_methods);
|
||||||
|
ADD_INT_MACRO(Py_mod_state_traverse);
|
||||||
|
ADD_INT_MACRO(Py_mod_state_clear);
|
||||||
|
ADD_INT_MACRO(Py_mod_state_free);
|
||||||
|
ADD_INT_MACRO(Py_mod_token);
|
||||||
|
#undef ADD_INT_MACRO
|
||||||
|
if (PyModule_Add(m, "module_test_token",
|
||||||
|
PyLong_FromVoidPtr((void*)&test_token)) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return PyModule_AddFunctions(m, test_methods);
|
||||||
|
}
|
||||||
|
|
@ -66,5 +66,6 @@ int _PyTestCapi_Init_Import(PyObject *mod);
|
||||||
int _PyTestCapi_Init_Frame(PyObject *mod);
|
int _PyTestCapi_Init_Frame(PyObject *mod);
|
||||||
int _PyTestCapi_Init_Type(PyObject *mod);
|
int _PyTestCapi_Init_Type(PyObject *mod);
|
||||||
int _PyTestCapi_Init_Function(PyObject *mod);
|
int _PyTestCapi_Init_Function(PyObject *mod);
|
||||||
|
int _PyTestCapi_Init_Module(PyObject *mod);
|
||||||
|
|
||||||
#endif // Py_TESTCAPI_PARTS_H
|
#endif // Py_TESTCAPI_PARTS_H
|
||||||
|
|
|
||||||
|
|
@ -3512,6 +3512,9 @@ _testcapi_exec(PyObject *m)
|
||||||
if (_PyTestCapi_Init_Function(m) < 0) {
|
if (_PyTestCapi_Init_Function(m) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (_PyTestCapi_Init_Module(m) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2418,6 +2418,34 @@ set_vectorcall_nop(PyObject *self, PyObject *func)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
module_get_gc_hooks(PyObject *self, PyObject *arg)
|
||||||
|
{
|
||||||
|
PyModuleObject *mod = (PyModuleObject *)arg;
|
||||||
|
PyObject *traverse = NULL;
|
||||||
|
PyObject *clear = NULL;
|
||||||
|
PyObject *free = NULL;
|
||||||
|
PyObject *result = NULL;
|
||||||
|
traverse = PyLong_FromVoidPtr(mod->md_state_traverse);
|
||||||
|
if (!traverse) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
clear = PyLong_FromVoidPtr(mod->md_state_clear);
|
||||||
|
if (!clear) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
free = PyLong_FromVoidPtr(mod->md_state_free);
|
||||||
|
if (!free) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
result = PyTuple_FromArray((PyObject*[]){ traverse, clear, free }, 3);
|
||||||
|
finally:
|
||||||
|
Py_XDECREF(traverse);
|
||||||
|
Py_XDECREF(clear);
|
||||||
|
Py_XDECREF(free);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef module_functions[] = {
|
static PyMethodDef module_functions[] = {
|
||||||
{"get_configs", get_configs, METH_NOARGS},
|
{"get_configs", get_configs, METH_NOARGS},
|
||||||
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
|
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
|
||||||
|
|
@ -2527,6 +2555,7 @@ static PyMethodDef module_functions[] = {
|
||||||
#endif
|
#endif
|
||||||
{"simple_pending_call", simple_pending_call, METH_O},
|
{"simple_pending_call", simple_pending_call, METH_O},
|
||||||
{"set_vectorcall_nop", set_vectorcall_nop, METH_O},
|
{"set_vectorcall_nop", set_vectorcall_nop, METH_O},
|
||||||
|
{"module_get_gc_hooks", module_get_gc_hooks, METH_O},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -850,6 +850,28 @@ PyInit__testmultiphase_exec_unreported_exception(void)
|
||||||
return PyModuleDef_Init(&def_exec_unreported_exception);
|
return PyModuleDef_Init(&def_exec_unreported_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int execfn_a1(PyObject*m) { return PyModule_AddIntConstant(m, "a", 1); }
|
||||||
|
static int execfn_b2(PyObject*m) { return PyModule_AddIntConstant(m, "b", 2); }
|
||||||
|
static int execfn_c3(PyObject*m) { return PyModule_AddIntConstant(m, "c", 3); }
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyInit__testmultiphase_exec_multiple(void)
|
||||||
|
{
|
||||||
|
static PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_exec, execfn_a1},
|
||||||
|
{Py_mod_exec, execfn_b2},
|
||||||
|
{Py_mod_exec, execfn_c3},
|
||||||
|
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
static PyModuleDef def = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
.m_name="_testmultiphase_exec_multiple",
|
||||||
|
.m_slots=slots,
|
||||||
|
};
|
||||||
|
return PyModuleDef_Init(&def);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
meth_state_access_exec(PyObject *m)
|
meth_state_access_exec(PyObject *m)
|
||||||
{
|
{
|
||||||
|
|
@ -993,3 +1015,156 @@ PyInit__test_no_multiple_interpreter_slot(void)
|
||||||
{
|
{
|
||||||
return PyModuleDef_Init(&no_multiple_interpreter_slot_def);
|
return PyModuleDef_Init(&no_multiple_interpreter_slot_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* PyModExport_* hooks */
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC
|
||||||
|
PyModExport__test_from_modexport(void)
|
||||||
|
{
|
||||||
|
static PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_name, "_test_from_modexport"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC
|
||||||
|
PyModExport__test_from_modexport_null(void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyModInit__test_from_modexport_null(void)
|
||||||
|
{
|
||||||
|
// This is not called as fallback for failed PyModExport_*
|
||||||
|
assert(0);
|
||||||
|
PyErr_SetString(PyExc_AssertionError, "PyInit_ fallback called");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC
|
||||||
|
PyModExport__test_from_modexport_exception(void)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "failed as requested");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyModInit__test_from_modexport_exception(void)
|
||||||
|
{
|
||||||
|
// This is not called as fallback for failed PyModExport_*
|
||||||
|
assert(0);
|
||||||
|
PyErr_SetString(PyExc_AssertionError, "PyInit_ fallback called");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
modexport_create_string(PyObject *spec, PyObject *def)
|
||||||
|
{
|
||||||
|
assert(def == NULL);
|
||||||
|
return PyUnicode_FromString("is this \xf0\x9f\xa6\x8b... a module?");
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC
|
||||||
|
PyModExport__test_from_modexport_create_nonmodule(void)
|
||||||
|
{
|
||||||
|
static PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_name, "_test_from_modexport_create_nonmodule"},
|
||||||
|
{Py_mod_create, modexport_create_string},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyModuleDef_Slot modexport_empty_slots[] = {
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC
|
||||||
|
PyModExport__test_from_modexport_empty_slots(void)
|
||||||
|
{
|
||||||
|
return modexport_empty_slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
modexport_smoke_exec(PyObject *mod)
|
||||||
|
{
|
||||||
|
// "magic" values 147 & 258 are expected in the test
|
||||||
|
if (PyModule_AddIntConstant(mod, "number", 147) < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int *state = PyModule_GetState(mod);
|
||||||
|
if (!state) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*state = 258;
|
||||||
|
|
||||||
|
PyObject *tp = PyType_FromModuleAndSpec(mod, &StateAccessType_spec, NULL);
|
||||||
|
if (PyModule_Add(mod, "Example", tp) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
modexport_smoke_get_state_int(PyObject *mod, PyObject *arg)
|
||||||
|
{
|
||||||
|
int *state = PyModule_GetState(mod);
|
||||||
|
if (!state) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyLong_FromLong(*state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char modexport_smoke_test_token;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
modexport_smoke_get_test_token(PyObject *mod, PyObject *arg)
|
||||||
|
{
|
||||||
|
return PyLong_FromVoidPtr((void*)&modexport_smoke_test_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
modexport_get_empty_slots(PyObject *mod, PyObject *arg)
|
||||||
|
{
|
||||||
|
/* Get the address of modexport_empty_slots.
|
||||||
|
* This method would be in the `_test_from_modexport_empty_slots` module,
|
||||||
|
* if it had a methods slot.
|
||||||
|
*/
|
||||||
|
return PyLong_FromVoidPtr(&modexport_empty_slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
modexport_smoke_free(PyObject *mod)
|
||||||
|
{
|
||||||
|
int *state = PyModule_GetState(mod);
|
||||||
|
if (!state) {
|
||||||
|
PyErr_FormatUnraisable("Exception ignored in module %R free", mod);
|
||||||
|
}
|
||||||
|
assert(*state == 258);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC
|
||||||
|
PyModExport__test_from_modexport_smoke(void)
|
||||||
|
{
|
||||||
|
static PyMethodDef methods[] = {
|
||||||
|
{"get_state_int", modexport_smoke_get_state_int, METH_NOARGS},
|
||||||
|
{"get_test_token", modexport_smoke_get_test_token, METH_NOARGS},
|
||||||
|
{"get_modexport_empty_slots", modexport_get_empty_slots, METH_NOARGS},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
static PyModuleDef_Slot slots[] = {
|
||||||
|
{Py_mod_name, "_test_from_modexport_smoke"},
|
||||||
|
{Py_mod_doc, "the expected docstring"},
|
||||||
|
{Py_mod_exec, modexport_smoke_exec},
|
||||||
|
{Py_mod_state_size, (void*)sizeof(int)},
|
||||||
|
{Py_mod_methods, methods},
|
||||||
|
{Py_mod_state_free, modexport_smoke_free},
|
||||||
|
{Py_mod_token, (void*)&modexport_smoke_test_token},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,8 @@ static inline module_state *
|
||||||
get_module_state(PyObject *module)
|
get_module_state(PyObject *module)
|
||||||
{
|
{
|
||||||
PyModuleDef *def = PyModule_GetDef(module);
|
PyModuleDef *def = PyModule_GetDef(module);
|
||||||
|
assert(def);
|
||||||
|
|
||||||
if (def->m_size == -1) {
|
if (def->m_size == -1) {
|
||||||
return &global_state.module;
|
return &global_state.module;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include "pycore_interp.h" // PyInterpreterState.importlib
|
#include "pycore_interp.h" // PyInterpreterState.importlib
|
||||||
#include "pycore_long.h" // _PyLong_GetOne()
|
#include "pycore_long.h" // _PyLong_GetOne()
|
||||||
#include "pycore_modsupport.h" // _PyModule_CreateInitialized()
|
#include "pycore_modsupport.h" // _PyModule_CreateInitialized()
|
||||||
#include "pycore_moduleobject.h" // _PyModule_GetDef()
|
#include "pycore_moduleobject.h" // _PyModule_GetDefOrNull()
|
||||||
#include "pycore_object.h" // _PyType_AllocNoTrack
|
#include "pycore_object.h" // _PyType_AllocNoTrack
|
||||||
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
|
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
|
||||||
#include "pycore_pystate.h" // _PyInterpreterState_GET()
|
#include "pycore_pystate.h" // _PyInterpreterState_GET()
|
||||||
|
|
@ -27,6 +27,27 @@ static PyMemberDef module_members[] = {
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
assert_def_missing_or_redundant(PyModuleObject *m)
|
||||||
|
{
|
||||||
|
/* We copy all relevant info into the module object.
|
||||||
|
* Modules created using a def keep a reference to that (statically
|
||||||
|
* allocated) def; the info there should match what we have in the module.
|
||||||
|
*/
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (m->md_token_is_def) {
|
||||||
|
PyModuleDef *def = (PyModuleDef *)m->md_token;
|
||||||
|
assert(def);
|
||||||
|
#define DO_ASSERT(F) assert (def->m_ ## F == m->md_state_ ## F);
|
||||||
|
DO_ASSERT(size);
|
||||||
|
DO_ASSERT(traverse);
|
||||||
|
DO_ASSERT(clear);
|
||||||
|
DO_ASSERT(free);
|
||||||
|
#undef DO_ASSERT
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyTypeObject PyModuleDef_Type = {
|
PyTypeObject PyModuleDef_Type = {
|
||||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
|
|
@ -44,8 +65,14 @@ _PyModule_IsExtension(PyObject *obj)
|
||||||
}
|
}
|
||||||
PyModuleObject *module = (PyModuleObject*)obj;
|
PyModuleObject *module = (PyModuleObject*)obj;
|
||||||
|
|
||||||
PyModuleDef *def = module->md_def;
|
if (module->md_exec) {
|
||||||
return (def != NULL && def->m_methods != NULL);
|
return 1;
|
||||||
|
}
|
||||||
|
if (module->md_token_is_def) {
|
||||||
|
PyModuleDef *def = (PyModuleDef *)module->md_token;
|
||||||
|
return (module->md_token_is_def && def->m_methods != NULL);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -146,10 +173,19 @@ new_module_notrack(PyTypeObject *mt)
|
||||||
m = (PyModuleObject *)_PyType_AllocNoTrack(mt, 0);
|
m = (PyModuleObject *)_PyType_AllocNoTrack(mt, 0);
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
m->md_def = NULL;
|
|
||||||
m->md_state = NULL;
|
m->md_state = NULL;
|
||||||
m->md_weaklist = NULL;
|
m->md_weaklist = NULL;
|
||||||
m->md_name = NULL;
|
m->md_name = NULL;
|
||||||
|
m->md_token_is_def = false;
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
m->md_gil = Py_MOD_GIL_USED;
|
||||||
|
#endif
|
||||||
|
m->md_state_size = 0;
|
||||||
|
m->md_state_traverse = NULL;
|
||||||
|
m->md_state_clear = NULL;
|
||||||
|
m->md_state_free = NULL;
|
||||||
|
m->md_exec = NULL;
|
||||||
|
m->md_token = NULL;
|
||||||
m->md_dict = PyDict_New();
|
m->md_dict = PyDict_New();
|
||||||
if (m->md_dict == NULL) {
|
if (m->md_dict == NULL) {
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
|
|
@ -264,6 +300,17 @@ PyModule_Create2(PyModuleDef* module, int module_api_version)
|
||||||
return _PyModule_CreateInitialized(module, module_api_version);
|
return _PyModule_CreateInitialized(module, module_api_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
module_copy_members_from_deflike(
|
||||||
|
PyModuleObject *md,
|
||||||
|
PyModuleDef *def_like /* not necessarily a valid Python object */)
|
||||||
|
{
|
||||||
|
md->md_state_size = def_like->m_size;
|
||||||
|
md->md_state_traverse = def_like->m_traverse;
|
||||||
|
md->md_state_clear = def_like->m_clear;
|
||||||
|
md->md_state_free = def_like->m_free;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyModule_CreateInitialized(PyModuleDef* module, int module_api_version)
|
_PyModule_CreateInitialized(PyModuleDef* module, int module_api_version)
|
||||||
{
|
{
|
||||||
|
|
@ -310,15 +357,21 @@ _PyModule_CreateInitialized(PyModuleDef* module, int module_api_version)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m->md_def = module;
|
m->md_token = module;
|
||||||
|
m->md_token_is_def = true;
|
||||||
|
module_copy_members_from_deflike(m, module);
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
m->md_gil = Py_MOD_GIL_USED;
|
m->md_gil = Py_MOD_GIL_USED;
|
||||||
#endif
|
#endif
|
||||||
return (PyObject*)m;
|
return (PyObject*)m;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_version)
|
module_from_def_and_spec(
|
||||||
|
PyModuleDef* def_like, /* not necessarily a valid Python object */
|
||||||
|
PyObject *spec,
|
||||||
|
int module_api_version,
|
||||||
|
PyModuleDef* original_def /* NULL if not defined by a def */)
|
||||||
{
|
{
|
||||||
PyModuleDef_Slot* cur_slot;
|
PyModuleDef_Slot* cur_slot;
|
||||||
PyObject *(*create)(PyObject *, PyModuleDef*) = NULL;
|
PyObject *(*create)(PyObject *, PyModuleDef*) = NULL;
|
||||||
|
|
@ -331,10 +384,10 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
int has_execution_slots = 0;
|
int has_execution_slots = 0;
|
||||||
const char *name;
|
const char *name;
|
||||||
int ret;
|
int ret;
|
||||||
|
void *token = NULL;
|
||||||
|
_Py_modexecfunc m_exec = NULL;
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
|
|
||||||
PyModuleDef_Init(def);
|
|
||||||
|
|
||||||
nameobj = PyObject_GetAttrString(spec, "name");
|
nameobj = PyObject_GetAttrString(spec, "name");
|
||||||
if (nameobj == NULL) {
|
if (nameobj == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -348,7 +401,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def->m_size < 0) {
|
if (def_like->m_size < 0) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
PyExc_SystemError,
|
PyExc_SystemError,
|
||||||
"module %s: m_size may not be negative for multi-phase initialization",
|
"module %s: m_size may not be negative for multi-phase initialization",
|
||||||
|
|
@ -356,7 +409,35 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) {
|
for (cur_slot = def_like->m_slots; cur_slot && cur_slot->slot; cur_slot++) {
|
||||||
|
// Macro to copy a non-NULL, non-repeatable slot that's unusable with
|
||||||
|
// PyModuleDef. The destination must be initially NULL.
|
||||||
|
#define COPY_COMMON_SLOT(SLOT, TYPE, DEST) \
|
||||||
|
do { \
|
||||||
|
if (!(TYPE)(cur_slot->value)) { \
|
||||||
|
PyErr_Format( \
|
||||||
|
PyExc_SystemError, \
|
||||||
|
"module %s: " #SLOT " must not be NULL", \
|
||||||
|
name); \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
if (original_def) { \
|
||||||
|
PyErr_Format( \
|
||||||
|
PyExc_SystemError, \
|
||||||
|
"module %s: " #SLOT " used with PyModuleDef", \
|
||||||
|
name); \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
if (DEST) { \
|
||||||
|
PyErr_Format( \
|
||||||
|
PyExc_SystemError, \
|
||||||
|
"module %s has more than one " #SLOT " slot", \
|
||||||
|
name); \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
DEST = (TYPE)(cur_slot->value); \
|
||||||
|
} while (0); \
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
switch (cur_slot->slot) {
|
switch (cur_slot->slot) {
|
||||||
case Py_mod_create:
|
case Py_mod_create:
|
||||||
if (create) {
|
if (create) {
|
||||||
|
|
@ -370,6 +451,9 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
break;
|
break;
|
||||||
case Py_mod_exec:
|
case Py_mod_exec:
|
||||||
has_execution_slots = 1;
|
has_execution_slots = 1;
|
||||||
|
if (!original_def) {
|
||||||
|
COPY_COMMON_SLOT(Py_mod_exec, _Py_modexecfunc, m_exec);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Py_mod_multiple_interpreters:
|
case Py_mod_multiple_interpreters:
|
||||||
if (has_multiple_interpreters_slot) {
|
if (has_multiple_interpreters_slot) {
|
||||||
|
|
@ -398,6 +482,35 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Py_mod_name:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_name, char*, def_like->m_name);
|
||||||
|
break;
|
||||||
|
case Py_mod_doc:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_doc, char*, def_like->m_doc);
|
||||||
|
break;
|
||||||
|
case Py_mod_state_size:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_state_size, Py_ssize_t,
|
||||||
|
def_like->m_size);
|
||||||
|
break;
|
||||||
|
case Py_mod_methods:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_methods, PyMethodDef*,
|
||||||
|
def_like->m_methods);
|
||||||
|
break;
|
||||||
|
case Py_mod_state_traverse:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_state_traverse, traverseproc,
|
||||||
|
def_like->m_traverse);
|
||||||
|
break;
|
||||||
|
case Py_mod_state_clear:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_state_clear, inquiry,
|
||||||
|
def_like->m_clear);
|
||||||
|
break;
|
||||||
|
case Py_mod_state_free:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_state_free, freefunc,
|
||||||
|
def_like->m_free);
|
||||||
|
break;
|
||||||
|
case Py_mod_token:
|
||||||
|
COPY_COMMON_SLOT(Py_mod_token, void*, token);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT);
|
assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT);
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
|
@ -406,6 +519,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
name, cur_slot->slot);
|
name, cur_slot->slot);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
#undef COPY_COMMON_SLOT
|
||||||
}
|
}
|
||||||
|
|
||||||
/* By default, multi-phase init modules are expected
|
/* By default, multi-phase init modules are expected
|
||||||
|
|
@ -429,7 +543,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create) {
|
if (create) {
|
||||||
m = create(spec, def);
|
m = create(spec, original_def);
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
if (!PyErr_Occurred()) {
|
if (!PyErr_Occurred()) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
|
@ -455,15 +569,27 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyModule_Check(m)) {
|
if (PyModule_Check(m)) {
|
||||||
((PyModuleObject*)m)->md_state = NULL;
|
PyModuleObject *mod = (PyModuleObject*)m;
|
||||||
((PyModuleObject*)m)->md_def = def;
|
mod->md_state = NULL;
|
||||||
|
module_copy_members_from_deflike(mod, def_like);
|
||||||
|
if (original_def) {
|
||||||
|
assert (!token);
|
||||||
|
mod->md_token = original_def;
|
||||||
|
mod->md_token_is_def = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mod->md_token = token;
|
||||||
|
}
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
((PyModuleObject*)m)->md_gil = gil_slot;
|
mod->md_gil = gil_slot;
|
||||||
#else
|
#else
|
||||||
(void)gil_slot;
|
(void)gil_slot;
|
||||||
#endif
|
#endif
|
||||||
|
mod->md_exec = m_exec;
|
||||||
} else {
|
} else {
|
||||||
if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) {
|
if (def_like->m_size > 0 || def_like->m_traverse || def_like->m_clear
|
||||||
|
|| def_like->m_free)
|
||||||
|
{
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
PyExc_SystemError,
|
PyExc_SystemError,
|
||||||
"module %s is not a module object, but requests module state",
|
"module %s is not a module object, but requests module state",
|
||||||
|
|
@ -478,17 +604,25 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
name);
|
name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (token) {
|
||||||
|
PyErr_Format(
|
||||||
|
PyExc_SystemError,
|
||||||
|
"module %s specifies a token, but did not create "
|
||||||
|
"a ModuleType instance",
|
||||||
|
name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def->m_methods != NULL) {
|
if (def_like->m_methods != NULL) {
|
||||||
ret = _add_methods_to_object(m, nameobj, def->m_methods);
|
ret = _add_methods_to_object(m, nameobj, def_like->m_methods);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def->m_doc != NULL) {
|
if (def_like->m_doc != NULL) {
|
||||||
ret = PyModule_SetDocString(m, def->m_doc);
|
ret = PyModule_SetDocString(m, def_like->m_doc);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
@ -503,6 +637,29 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_version)
|
||||||
|
{
|
||||||
|
PyModuleDef_Init(def);
|
||||||
|
return module_from_def_and_spec(def, spec, module_api_version, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots, PyObject *spec)
|
||||||
|
{
|
||||||
|
if (!slots) {
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_SystemError,
|
||||||
|
"PyModule_FromSlotsAndSpec called with NULL slots");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// Fill in enough of a PyModuleDef to pass to common machinery
|
||||||
|
PyModuleDef def_like = {.m_slots = (PyModuleDef_Slot *)slots};
|
||||||
|
|
||||||
|
return module_from_def_and_spec(&def_like, spec, PYTHON_API_VERSION,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
int
|
int
|
||||||
PyUnstable_Module_SetGIL(PyObject *module, void *gil)
|
PyUnstable_Module_SetGIL(PyObject *module, void *gil)
|
||||||
|
|
@ -516,71 +673,94 @@ PyUnstable_Module_SetGIL(PyObject *module, void *gil)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
static int
|
||||||
PyModule_ExecDef(PyObject *module, PyModuleDef *def)
|
run_exec_func(PyObject *module, int (*exec)(PyObject *))
|
||||||
{
|
{
|
||||||
PyModuleDef_Slot *cur_slot;
|
int ret = exec(module);
|
||||||
const char *name;
|
if (ret != 0) {
|
||||||
int ret;
|
if (!PyErr_Occurred()) {
|
||||||
|
PyErr_Format(
|
||||||
name = PyModule_GetName(module);
|
PyExc_SystemError,
|
||||||
if (name == NULL) {
|
"execution of %R failed without setting an exception",
|
||||||
|
module);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
_PyErr_FormatFromCause(
|
||||||
|
PyExc_SystemError,
|
||||||
|
"execution of module %R raised unreported exception",
|
||||||
|
module);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (def->m_size >= 0) {
|
static int
|
||||||
PyModuleObject *md = (PyModuleObject*)module;
|
alloc_state(PyObject *module)
|
||||||
|
{
|
||||||
|
if (!PyModule_Check(module)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected module, got %T", module);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyModuleObject *md = (PyModuleObject*)module;
|
||||||
|
|
||||||
|
if (md->md_state_size >= 0) {
|
||||||
if (md->md_state == NULL) {
|
if (md->md_state == NULL) {
|
||||||
/* Always set a state pointer; this serves as a marker to skip
|
/* Always set a state pointer; this serves as a marker to skip
|
||||||
* multiple initialization (importlib.reload() is no-op) */
|
* multiple initialization (importlib.reload() is no-op) */
|
||||||
md->md_state = PyMem_Malloc(def->m_size);
|
md->md_state = PyMem_Malloc(md->md_state_size);
|
||||||
if (!md->md_state) {
|
if (!md->md_state) {
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset(md->md_state, 0, def->m_size);
|
memset(md->md_state, 0, md->md_state_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyModule_Exec(PyObject *module)
|
||||||
|
{
|
||||||
|
if (alloc_state(module) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyModuleObject *md = (PyModuleObject*)module;
|
||||||
|
if (md->md_exec) {
|
||||||
|
assert(!md->md_token_is_def);
|
||||||
|
return run_exec_func(module, md->md_exec);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyModuleDef *def = _PyModule_GetDefOrNull(module);
|
||||||
|
if (def) {
|
||||||
|
return PyModule_ExecDef(module, def);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyModule_ExecDef(PyObject *module, PyModuleDef *def)
|
||||||
|
{
|
||||||
|
PyModuleDef_Slot *cur_slot;
|
||||||
|
|
||||||
|
if (alloc_state(module) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(PyModule_Check(module));
|
||||||
|
|
||||||
if (def->m_slots == NULL) {
|
if (def->m_slots == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) {
|
for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) {
|
||||||
switch (cur_slot->slot) {
|
if (cur_slot->slot == Py_mod_exec) {
|
||||||
case Py_mod_create:
|
int (*func)(PyObject *) = cur_slot->value;
|
||||||
/* handled in PyModule_FromDefAndSpec2 */
|
if (run_exec_func(module, func) < 0) {
|
||||||
break;
|
|
||||||
case Py_mod_exec:
|
|
||||||
ret = ((int (*)(PyObject *))cur_slot->value)(module);
|
|
||||||
if (ret != 0) {
|
|
||||||
if (!PyErr_Occurred()) {
|
|
||||||
PyErr_Format(
|
|
||||||
PyExc_SystemError,
|
|
||||||
"execution of module %s failed without setting an exception",
|
|
||||||
name);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
_PyErr_FormatFromCause(
|
|
||||||
PyExc_SystemError,
|
|
||||||
"execution of module %s raised unreported exception",
|
|
||||||
name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Py_mod_multiple_interpreters:
|
|
||||||
case Py_mod_gil:
|
|
||||||
case Py_mod_abi:
|
|
||||||
/* handled in PyModule_FromDefAndSpec2 */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PyErr_Format(
|
|
||||||
PyExc_SystemError,
|
|
||||||
"module %s initialized with unknown slot %i",
|
|
||||||
name, cur_slot->slot);
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -624,6 +804,31 @@ PyModule_GetDict(PyObject *m)
|
||||||
return _PyModule_GetDict(m); // borrowed reference
|
return _PyModule_GetDict(m); // borrowed reference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyModule_GetStateSize(PyObject *m, Py_ssize_t *size_p)
|
||||||
|
{
|
||||||
|
*size_p = -1;
|
||||||
|
if (!PyModule_Check(m)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected module, got %T", m);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyModuleObject *mod = (PyModuleObject *)m;
|
||||||
|
*size_p = mod->md_state_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyModule_GetToken(PyObject *m, void **token_p)
|
||||||
|
{
|
||||||
|
*token_p = NULL;
|
||||||
|
if (!PyModule_Check(m)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected module, got %T", m);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*token_p = _PyModule_GetToken(m);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyModule_GetNameObject(PyObject *mod)
|
PyModule_GetNameObject(PyObject *mod)
|
||||||
{
|
{
|
||||||
|
|
@ -764,7 +969,7 @@ PyModule_GetDef(PyObject* m)
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return _PyModule_GetDef(m);
|
return _PyModule_GetDefOrNull(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
|
|
@ -888,17 +1093,18 @@ module_dealloc(PyObject *self)
|
||||||
}
|
}
|
||||||
FT_CLEAR_WEAKREFS(self, m->md_weaklist);
|
FT_CLEAR_WEAKREFS(self, m->md_weaklist);
|
||||||
|
|
||||||
|
assert_def_missing_or_redundant(m);
|
||||||
/* bpo-39824: Don't call m_free() if m_size > 0 and md_state=NULL */
|
/* bpo-39824: Don't call m_free() if m_size > 0 and md_state=NULL */
|
||||||
if (m->md_def && m->md_def->m_free
|
if (m->md_state_free && (m->md_state_size <= 0 || m->md_state != NULL))
|
||||||
&& (m->md_def->m_size <= 0 || m->md_state != NULL))
|
|
||||||
{
|
{
|
||||||
m->md_def->m_free(m);
|
m->md_state_free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_XDECREF(m->md_dict);
|
Py_XDECREF(m->md_dict);
|
||||||
Py_XDECREF(m->md_name);
|
Py_XDECREF(m->md_name);
|
||||||
if (m->md_state != NULL)
|
if (m->md_state != NULL) {
|
||||||
PyMem_Free(m->md_state);
|
PyMem_Free(m->md_state);
|
||||||
|
}
|
||||||
Py_TYPE(m)->tp_free((PyObject *)m);
|
Py_TYPE(m)->tp_free((PyObject *)m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1206,11 +1412,11 @@ module_traverse(PyObject *self, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
PyModuleObject *m = _PyModule_CAST(self);
|
PyModuleObject *m = _PyModule_CAST(self);
|
||||||
|
|
||||||
|
assert_def_missing_or_redundant(m);
|
||||||
/* bpo-39824: Don't call m_traverse() if m_size > 0 and md_state=NULL */
|
/* bpo-39824: Don't call m_traverse() if m_size > 0 and md_state=NULL */
|
||||||
if (m->md_def && m->md_def->m_traverse
|
if (m->md_state_traverse && (m->md_state_size <= 0 || m->md_state != NULL))
|
||||||
&& (m->md_def->m_size <= 0 || m->md_state != NULL))
|
|
||||||
{
|
{
|
||||||
int res = m->md_def->m_traverse((PyObject*)m, visit, arg);
|
int res = m->md_state_traverse((PyObject*)m, visit, arg);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -1224,18 +1430,19 @@ module_clear(PyObject *self)
|
||||||
{
|
{
|
||||||
PyModuleObject *m = _PyModule_CAST(self);
|
PyModuleObject *m = _PyModule_CAST(self);
|
||||||
|
|
||||||
|
assert_def_missing_or_redundant(m);
|
||||||
/* bpo-39824: Don't call m_clear() if m_size > 0 and md_state=NULL */
|
/* bpo-39824: Don't call m_clear() if m_size > 0 and md_state=NULL */
|
||||||
if (m->md_def && m->md_def->m_clear
|
if (m->md_state_clear && (m->md_state_size <= 0 || m->md_state != NULL))
|
||||||
&& (m->md_def->m_size <= 0 || m->md_state != NULL))
|
|
||||||
{
|
{
|
||||||
int res = m->md_def->m_clear((PyObject*)m);
|
int res = m->md_state_clear((PyObject*)m);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
PyErr_FormatUnraisable("Exception ignored in m_clear of module%s%V",
|
PyErr_FormatUnraisable("Exception ignored in m_clear of module%s%V",
|
||||||
m->md_name ? " " : "",
|
m->md_name ? " " : "",
|
||||||
m->md_name, "");
|
m->md_name, "");
|
||||||
}
|
}
|
||||||
if (res)
|
if (res) {
|
||||||
return res;
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_CLEAR(m->md_dict);
|
Py_CLEAR(m->md_dict);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -5764,11 +5764,11 @@ PyType_GetModuleState(PyTypeObject *type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the module of the first superclass where the module has the
|
/* Return borrowed ref to the module of the first superclass where the module
|
||||||
* given PyModuleDef.
|
* has the given token.
|
||||||
*/
|
*/
|
||||||
PyObject *
|
static PyObject *
|
||||||
PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
|
borrow_module_by_token(PyTypeObject *type, const void *token)
|
||||||
{
|
{
|
||||||
assert(PyType_Check(type));
|
assert(PyType_Check(type));
|
||||||
|
|
||||||
|
|
@ -5780,7 +5780,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
|
||||||
else {
|
else {
|
||||||
PyHeapTypeObject *ht = (PyHeapTypeObject*)type;
|
PyHeapTypeObject *ht = (PyHeapTypeObject*)type;
|
||||||
PyObject *module = ht->ht_module;
|
PyObject *module = ht->ht_module;
|
||||||
if (module && _PyModule_GetDef(module) == def) {
|
if (module && _PyModule_GetToken(module) == token) {
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5808,7 +5808,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
|
||||||
|
|
||||||
PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
|
PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
|
||||||
PyObject *module = ht->ht_module;
|
PyObject *module = ht->ht_module;
|
||||||
if (module && _PyModule_GetDef(module) == def) {
|
if (module && _PyModule_GetToken(module) == token) {
|
||||||
res = module;
|
res = module;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -5826,6 +5826,18 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
|
||||||
|
{
|
||||||
|
return borrow_module_by_token(type, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyType_GetModuleByToken(PyTypeObject *type, const void *token)
|
||||||
|
{
|
||||||
|
return Py_XNewRef(borrow_module_by_token(type, token));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyTypeObject *
|
static PyTypeObject *
|
||||||
get_base_by_token_recursive(PyObject *bases, void *token)
|
get_base_by_token_recursive(PyObject *bases, void *token)
|
||||||
|
|
|
||||||
5
PC/python3dll.c
generated
5
PC/python3dll.c
generated
|
|
@ -416,8 +416,10 @@ EXPORT_FUNC(PyModule_AddObjectRef)
|
||||||
EXPORT_FUNC(PyModule_AddStringConstant)
|
EXPORT_FUNC(PyModule_AddStringConstant)
|
||||||
EXPORT_FUNC(PyModule_AddType)
|
EXPORT_FUNC(PyModule_AddType)
|
||||||
EXPORT_FUNC(PyModule_Create2)
|
EXPORT_FUNC(PyModule_Create2)
|
||||||
|
EXPORT_FUNC(PyModule_Exec)
|
||||||
EXPORT_FUNC(PyModule_ExecDef)
|
EXPORT_FUNC(PyModule_ExecDef)
|
||||||
EXPORT_FUNC(PyModule_FromDefAndSpec2)
|
EXPORT_FUNC(PyModule_FromDefAndSpec2)
|
||||||
|
EXPORT_FUNC(PyModule_FromSlotsAndSpec)
|
||||||
EXPORT_FUNC(PyModule_GetDef)
|
EXPORT_FUNC(PyModule_GetDef)
|
||||||
EXPORT_FUNC(PyModule_GetDict)
|
EXPORT_FUNC(PyModule_GetDict)
|
||||||
EXPORT_FUNC(PyModule_GetFilename)
|
EXPORT_FUNC(PyModule_GetFilename)
|
||||||
|
|
@ -425,6 +427,8 @@ EXPORT_FUNC(PyModule_GetFilenameObject)
|
||||||
EXPORT_FUNC(PyModule_GetName)
|
EXPORT_FUNC(PyModule_GetName)
|
||||||
EXPORT_FUNC(PyModule_GetNameObject)
|
EXPORT_FUNC(PyModule_GetNameObject)
|
||||||
EXPORT_FUNC(PyModule_GetState)
|
EXPORT_FUNC(PyModule_GetState)
|
||||||
|
EXPORT_FUNC(PyModule_GetStateSize)
|
||||||
|
EXPORT_FUNC(PyModule_GetToken)
|
||||||
EXPORT_FUNC(PyModule_New)
|
EXPORT_FUNC(PyModule_New)
|
||||||
EXPORT_FUNC(PyModule_NewObject)
|
EXPORT_FUNC(PyModule_NewObject)
|
||||||
EXPORT_FUNC(PyModule_SetDocString)
|
EXPORT_FUNC(PyModule_SetDocString)
|
||||||
|
|
@ -668,6 +672,7 @@ EXPORT_FUNC(PyType_GetFlags)
|
||||||
EXPORT_FUNC(PyType_GetFullyQualifiedName)
|
EXPORT_FUNC(PyType_GetFullyQualifiedName)
|
||||||
EXPORT_FUNC(PyType_GetModule)
|
EXPORT_FUNC(PyType_GetModule)
|
||||||
EXPORT_FUNC(PyType_GetModuleByDef)
|
EXPORT_FUNC(PyType_GetModuleByDef)
|
||||||
|
EXPORT_FUNC(PyType_GetModuleByToken)
|
||||||
EXPORT_FUNC(PyType_GetModuleName)
|
EXPORT_FUNC(PyType_GetModuleName)
|
||||||
EXPORT_FUNC(PyType_GetModuleState)
|
EXPORT_FUNC(PyType_GetModuleState)
|
||||||
EXPORT_FUNC(PyType_GetName)
|
EXPORT_FUNC(PyType_GetName)
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@
|
||||||
<ClCompile Include="..\Modules\_testcapi\gc.c" />
|
<ClCompile Include="..\Modules\_testcapi\gc.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\run.c" />
|
<ClCompile Include="..\Modules\_testcapi\run.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\modsupport.c" />
|
<ClCompile Include="..\Modules\_testcapi\modsupport.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testcapi\module.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\monitoring.c" />
|
<ClCompile Include="..\Modules\_testcapi\monitoring.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\config.c" />
|
<ClCompile Include="..\Modules\_testcapi\config.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\import.c" />
|
<ClCompile Include="..\Modules\_testcapi\import.c" />
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,9 @@
|
||||||
<ClCompile Include="..\Modules\_testcapi\modsupport.c">
|
<ClCompile Include="..\Modules\_testcapi\modsupport.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Modules\_testcapi\module.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\Modules\_testcapi\monitoring.c">
|
<ClCompile Include="..\Modules\_testcapi\monitoring.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
||||||
113
Python/import.c
113
Python/import.c
|
|
@ -672,8 +672,8 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
|
||||||
|
|
||||||
(6). first time (not found in _PyRuntime.imports.extensions):
|
(6). first time (not found in _PyRuntime.imports.extensions):
|
||||||
A. _imp_create_dynamic_impl() -> import_find_extension()
|
A. _imp_create_dynamic_impl() -> import_find_extension()
|
||||||
B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc()
|
B. _imp_create_dynamic_impl() -> _PyImport_GetModuleExportHooks()
|
||||||
C. _PyImport_GetModInitFunc(): load <module init func>
|
C. _PyImport_GetModuleExportHooks(): load <module init func>
|
||||||
D. _imp_create_dynamic_impl() -> import_run_extension()
|
D. _imp_create_dynamic_impl() -> import_run_extension()
|
||||||
E. import_run_extension() -> _PyImport_RunModInitFunc()
|
E. import_run_extension() -> _PyImport_RunModInitFunc()
|
||||||
F. _PyImport_RunModInitFunc(): call <module init func>
|
F. _PyImport_RunModInitFunc(): call <module init func>
|
||||||
|
|
@ -743,16 +743,19 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
|
||||||
A. noop
|
A. noop
|
||||||
|
|
||||||
|
|
||||||
...for multi-phase init modules:
|
...for multi-phase init modules from PyModInit_* (PyModuleDef):
|
||||||
|
|
||||||
(6). every time:
|
(6). every time:
|
||||||
A. _imp_create_dynamic_impl() -> import_find_extension() (not found)
|
A. _imp_create_dynamic_impl() -> import_find_extension() (not found)
|
||||||
B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc()
|
B. _imp_create_dynamic_impl() -> _PyImport_GetModuleExportHooks()
|
||||||
C. _PyImport_GetModInitFunc(): load <module init func>
|
C. _PyImport_GetModuleExportHooks(): load <module init func>
|
||||||
D. _imp_create_dynamic_impl() -> import_run_extension()
|
D. _imp_create_dynamic_impl() -> import_run_extension()
|
||||||
E. import_run_extension() -> _PyImport_RunModInitFunc()
|
E. import_run_extension() -> _PyImport_RunModInitFunc()
|
||||||
F. _PyImport_RunModInitFunc(): call <module init func>
|
F. _PyImport_RunModInitFunc(): call <module init func>
|
||||||
G. import_run_extension() -> PyModule_FromDefAndSpec()
|
G. import_run_extension() -> PyModule_FromDefAndSpec()
|
||||||
|
|
||||||
|
PyModule_FromDefAndSpec():
|
||||||
|
|
||||||
H. PyModule_FromDefAndSpec(): gather/check moduledef slots
|
H. PyModule_FromDefAndSpec(): gather/check moduledef slots
|
||||||
I. if there's a Py_mod_create slot:
|
I. if there's a Py_mod_create slot:
|
||||||
1. PyModule_FromDefAndSpec(): call its function
|
1. PyModule_FromDefAndSpec(): call its function
|
||||||
|
|
@ -765,10 +768,29 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
|
||||||
(10). every time:
|
(10). every time:
|
||||||
A. _imp_exec_dynamic_impl() -> exec_builtin_or_dynamic()
|
A. _imp_exec_dynamic_impl() -> exec_builtin_or_dynamic()
|
||||||
B. if mod->md_state == NULL (including if m_size == 0):
|
B. if mod->md_state == NULL (including if m_size == 0):
|
||||||
1. exec_builtin_or_dynamic() -> PyModule_ExecDef()
|
1. exec_builtin_or_dynamic() -> PyModule_Exec()
|
||||||
2. PyModule_ExecDef(): allocate mod->md_state
|
2. PyModule_Exec(): allocate mod->md_state
|
||||||
3. if there's a Py_mod_exec slot:
|
3. if there's a Py_mod_exec slot:
|
||||||
1. PyModule_ExecDef(): call its function
|
1. PyModule_Exec(): call its function
|
||||||
|
|
||||||
|
|
||||||
|
...for multi-phase init modules from PyModExport_* (slots array):
|
||||||
|
|
||||||
|
(6). every time:
|
||||||
|
|
||||||
|
A. _imp_create_dynamic_impl() -> import_find_extension() (not found)
|
||||||
|
B. _imp_create_dynamic_impl() -> _PyImport_GetModuleExportHooks()
|
||||||
|
C. _PyImport_GetModuleExportHooks(): load <module export func>
|
||||||
|
D. _imp_create_dynamic_impl() -> import_run_modexport()
|
||||||
|
E. import_run_modexport(): call <module init func>
|
||||||
|
F. import_run_modexport() -> PyModule_FromSlotsAndSpec()
|
||||||
|
G. PyModule_FromSlotsAndSpec(): create temporary PyModuleDef-like
|
||||||
|
H. PyModule_FromSlotsAndSpec() -> PyModule_FromDefAndSpec()
|
||||||
|
|
||||||
|
(PyModule_FromDefAndSpec behaves as for PyModInit_*, above)
|
||||||
|
|
||||||
|
(10). every time: as for PyModInit_*, above
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -825,25 +847,19 @@ _PyImport_SetDLOpenFlags(PyInterpreterState *interp, int new_val)
|
||||||
/* Common implementation for _imp.exec_dynamic and _imp.exec_builtin */
|
/* Common implementation for _imp.exec_dynamic and _imp.exec_builtin */
|
||||||
static int
|
static int
|
||||||
exec_builtin_or_dynamic(PyObject *mod) {
|
exec_builtin_or_dynamic(PyObject *mod) {
|
||||||
PyModuleDef *def;
|
|
||||||
void *state;
|
void *state;
|
||||||
|
|
||||||
if (!PyModule_Check(mod)) {
|
if (!PyModule_Check(mod)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
def = PyModule_GetDef(mod);
|
|
||||||
if (def == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = PyModule_GetState(mod);
|
state = PyModule_GetState(mod);
|
||||||
if (state) {
|
if (state) {
|
||||||
/* Already initialized; skip reload */
|
/* Already initialized; skip reload */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PyModule_ExecDef(mod, def);
|
return PyModule_Exec(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1787,7 +1803,7 @@ finish_singlephase_extension(PyThreadState *tstate, PyObject *mod,
|
||||||
PyObject *name, PyObject *modules)
|
PyObject *name, PyObject *modules)
|
||||||
{
|
{
|
||||||
assert(mod != NULL && PyModule_Check(mod));
|
assert(mod != NULL && PyModule_Check(mod));
|
||||||
assert(cached->def == _PyModule_GetDef(mod));
|
assert(cached->def == _PyModule_GetDefOrNull(mod));
|
||||||
|
|
||||||
Py_ssize_t index = _get_cached_module_index(cached);
|
Py_ssize_t index = _get_cached_module_index(cached);
|
||||||
if (_modules_by_index_set(tstate->interp, index, mod) < 0) {
|
if (_modules_by_index_set(tstate->interp, index, mod) < 0) {
|
||||||
|
|
@ -1865,8 +1881,8 @@ reload_singlephase_extension(PyThreadState *tstate,
|
||||||
* due to violating interpreter isolation.
|
* due to violating interpreter isolation.
|
||||||
* See the note in set_cached_m_dict().
|
* See the note in set_cached_m_dict().
|
||||||
* Until that is solved, we leave md_def set to NULL. */
|
* Until that is solved, we leave md_def set to NULL. */
|
||||||
assert(_PyModule_GetDef(mod) == NULL
|
assert(_PyModule_GetDefOrNull(mod) == NULL
|
||||||
|| _PyModule_GetDef(mod) == def);
|
|| _PyModule_GetDefOrNull(mod) == def);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(cached->m_dict == NULL);
|
assert(cached->m_dict == NULL);
|
||||||
|
|
@ -1953,6 +1969,43 @@ import_find_extension(PyThreadState *tstate,
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
import_run_modexport(PyThreadState *tstate, PyModExportFunction ex0,
|
||||||
|
struct _Py_ext_module_loader_info *info,
|
||||||
|
PyObject *spec)
|
||||||
|
{
|
||||||
|
/* This is like import_run_extension, but avoids interpreter switching
|
||||||
|
* and code for for single-phase modules.
|
||||||
|
*/
|
||||||
|
PyModuleDef_Slot *slots = ex0();
|
||||||
|
if (!slots) {
|
||||||
|
if (!PyErr_Occurred()) {
|
||||||
|
PyErr_Format(
|
||||||
|
PyExc_SystemError,
|
||||||
|
"slot export function for module %s failed without setting an exception",
|
||||||
|
info->name);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
PyErr_Format(
|
||||||
|
PyExc_SystemError,
|
||||||
|
"slot export function for module %s raised unreported exception",
|
||||||
|
info->name);
|
||||||
|
}
|
||||||
|
PyObject *result = PyModule_FromSlotsAndSpec(slots, spec);
|
||||||
|
if (!result) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (PyModule_Check(result)) {
|
||||||
|
PyModuleObject *mod = (PyModuleObject *)result;
|
||||||
|
if (mod && !mod->md_token) {
|
||||||
|
mod->md_token = slots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
|
import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
|
||||||
struct _Py_ext_module_loader_info *info,
|
struct _Py_ext_module_loader_info *info,
|
||||||
|
|
@ -2125,7 +2178,7 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
|
||||||
assert_multiphase_def(def);
|
assert_multiphase_def(def);
|
||||||
assert(mod == NULL);
|
assert(mod == NULL);
|
||||||
/* Note that we cheat a little by not repeating the calls
|
/* Note that we cheat a little by not repeating the calls
|
||||||
* to _PyImport_GetModInitFunc() and _PyImport_RunModInitFunc(). */
|
* to _PyImport_GetModuleExportHooks() and _PyImport_RunModInitFunc(). */
|
||||||
mod = PyModule_FromDefAndSpec(def, spec);
|
mod = PyModule_FromDefAndSpec(def, spec);
|
||||||
if (mod == NULL) {
|
if (mod == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -2239,8 +2292,9 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyModuleDef *def = PyModule_GetDef(mod);
|
PyModuleDef *def = _PyModule_GetDefOrNull(mod);
|
||||||
if (def == NULL) {
|
if (def == NULL) {
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
@ -2322,8 +2376,8 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
|
||||||
assert(!_PyErr_Occurred(tstate));
|
assert(!_PyErr_Occurred(tstate));
|
||||||
assert(cached != NULL);
|
assert(cached != NULL);
|
||||||
/* The module might not have md_def set in certain reload cases. */
|
/* The module might not have md_def set in certain reload cases. */
|
||||||
assert(_PyModule_GetDef(mod) == NULL
|
assert(_PyModule_GetDefOrNull(mod) == NULL
|
||||||
|| cached->def == _PyModule_GetDef(mod));
|
|| cached->def == _PyModule_GetDefOrNull(mod));
|
||||||
assert_singlephase(cached);
|
assert_singlephase(cached);
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
@ -4653,8 +4707,8 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
|
||||||
assert(!_PyErr_Occurred(tstate));
|
assert(!_PyErr_Occurred(tstate));
|
||||||
assert(cached != NULL);
|
assert(cached != NULL);
|
||||||
/* The module might not have md_def set in certain reload cases. */
|
/* The module might not have md_def set in certain reload cases. */
|
||||||
assert(_PyModule_GetDef(mod) == NULL
|
assert(_PyModule_GetDefOrNull(mod) == NULL
|
||||||
|| cached->def == _PyModule_GetDef(mod));
|
|| cached->def == _PyModule_GetDefOrNull(mod));
|
||||||
assert_singlephase(cached);
|
assert_singlephase(cached);
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
@ -4679,7 +4733,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We would move this (and the fclose() below) into
|
/* We would move this (and the fclose() below) into
|
||||||
* _PyImport_GetModInitFunc(), but it isn't clear if the intervening
|
* _PyImport_GetModuleExportHooks(), but it isn't clear if the intervening
|
||||||
* code relies on fp still being open. */
|
* code relies on fp still being open. */
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
if (file != NULL) {
|
if (file != NULL) {
|
||||||
|
|
@ -4692,7 +4746,13 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyModInitFunction p0 = _PyImport_GetModInitFunc(&info, fp);
|
PyModInitFunction p0 = NULL;
|
||||||
|
PyModExportFunction ex0 = NULL;
|
||||||
|
_PyImport_GetModuleExportHooks(&info, fp, &p0, &ex0);
|
||||||
|
if (ex0) {
|
||||||
|
mod = import_run_modexport(tstate, ex0, &info, spec);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
if (p0 == NULL) {
|
if (p0 == NULL) {
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
@ -4714,6 +4774,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cleanup:
|
||||||
// XXX Shouldn't this happen in the error cases too (i.e. in "finally")?
|
// XXX Shouldn't this happen in the error cases too (i.e. in "finally")?
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include "pycore_call.h" // _PyObject_CallMethod()
|
#include "pycore_call.h" // _PyObject_CallMethod()
|
||||||
#include "pycore_import.h" // _PyImport_SwapPackageContext()
|
#include "pycore_import.h" // _PyImport_SwapPackageContext()
|
||||||
#include "pycore_importdl.h"
|
#include "pycore_importdl.h"
|
||||||
#include "pycore_moduleobject.h" // _PyModule_GetDef()
|
#include "pycore_moduleobject.h" // _PyModule_GetDefOrNull()
|
||||||
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
|
#include "pycore_pyerrors.h" // _PyErr_FormatFromCause()
|
||||||
#include "pycore_runtime.h" // _Py_ID()
|
#include "pycore_runtime.h" // _Py_ID()
|
||||||
|
|
||||||
|
|
@ -35,8 +35,10 @@ extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix,
|
||||||
/* module info to use when loading */
|
/* module info to use when loading */
|
||||||
/***********************************/
|
/***********************************/
|
||||||
|
|
||||||
static const char * const ascii_only_prefix = "PyInit";
|
static const struct hook_prefixes ascii_only_prefixes = {
|
||||||
static const char * const nonascii_prefix = "PyInitU";
|
"PyInit", "PyModExport"};
|
||||||
|
static const struct hook_prefixes nonascii_prefixes = {
|
||||||
|
"PyInitU", "PyModExportU"};
|
||||||
|
|
||||||
/* Get the variable part of a module's export symbol name.
|
/* Get the variable part of a module's export symbol name.
|
||||||
* Returns a bytes instance. For non-ASCII-named modules, the name is
|
* Returns a bytes instance. For non-ASCII-named modules, the name is
|
||||||
|
|
@ -45,7 +47,7 @@ static const char * const nonascii_prefix = "PyInitU";
|
||||||
* nonascii_prefix, as appropriate.
|
* nonascii_prefix, as appropriate.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_encoded_name(PyObject *name, const char **hook_prefix) {
|
get_encoded_name(PyObject *name, const struct hook_prefixes **hook_prefixes) {
|
||||||
PyObject *tmp;
|
PyObject *tmp;
|
||||||
PyObject *encoded = NULL;
|
PyObject *encoded = NULL;
|
||||||
PyObject *modname = NULL;
|
PyObject *modname = NULL;
|
||||||
|
|
@ -72,7 +74,7 @@ get_encoded_name(PyObject *name, const char **hook_prefix) {
|
||||||
/* Encode to ASCII or Punycode, as needed */
|
/* Encode to ASCII or Punycode, as needed */
|
||||||
encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
|
encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
|
||||||
if (encoded != NULL) {
|
if (encoded != NULL) {
|
||||||
*hook_prefix = ascii_only_prefix;
|
*hook_prefixes = &ascii_only_prefixes;
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
|
if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
|
@ -80,7 +82,7 @@ get_encoded_name(PyObject *name, const char **hook_prefix) {
|
||||||
if (encoded == NULL) {
|
if (encoded == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
*hook_prefix = nonascii_prefix;
|
*hook_prefixes = &nonascii_prefixes;
|
||||||
} else {
|
} else {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +132,7 @@ _Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info,
|
||||||
assert(PyUnicode_GetLength(name) > 0);
|
assert(PyUnicode_GetLength(name) > 0);
|
||||||
info.name = Py_NewRef(name);
|
info.name = Py_NewRef(name);
|
||||||
|
|
||||||
info.name_encoded = get_encoded_name(info.name, &info.hook_prefix);
|
info.name_encoded = get_encoded_name(info.name, &info.hook_prefixes);
|
||||||
if (info.name_encoded == NULL) {
|
if (info.name_encoded == NULL) {
|
||||||
_Py_ext_module_loader_info_clear(&info);
|
_Py_ext_module_loader_info_clear(&info);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -189,7 +191,7 @@ _Py_ext_module_loader_info_init_for_builtin(
|
||||||
/* We won't need filename. */
|
/* We won't need filename. */
|
||||||
.path=name,
|
.path=name,
|
||||||
.origin=_Py_ext_module_origin_BUILTIN,
|
.origin=_Py_ext_module_origin_BUILTIN,
|
||||||
.hook_prefix=ascii_only_prefix,
|
.hook_prefixes=&ascii_only_prefixes,
|
||||||
.newcontext=NULL,
|
.newcontext=NULL,
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -377,39 +379,63 @@ _Py_ext_module_loader_result_apply_error(
|
||||||
/********************************************/
|
/********************************************/
|
||||||
|
|
||||||
#ifdef HAVE_DYNAMIC_LOADING
|
#ifdef HAVE_DYNAMIC_LOADING
|
||||||
PyModInitFunction
|
static dl_funcptr
|
||||||
_PyImport_GetModInitFunc(struct _Py_ext_module_loader_info *info,
|
findfuncptr(const char *prefix, const char *name_buf,
|
||||||
FILE *fp)
|
struct _Py_ext_module_loader_info *info,
|
||||||
|
FILE *fp)
|
||||||
{
|
{
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
return _PyImport_FindSharedFuncptrWindows(
|
||||||
|
prefix, name_buf, info->filename, fp);
|
||||||
|
#else
|
||||||
|
const char *path_buf = PyBytes_AS_STRING(info->filename_encoded);
|
||||||
|
return _PyImport_FindSharedFuncptr(
|
||||||
|
prefix, name_buf, path_buf, fp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyImport_GetModuleExportHooks(
|
||||||
|
struct _Py_ext_module_loader_info *info,
|
||||||
|
FILE *fp,
|
||||||
|
PyModInitFunction *modinit,
|
||||||
|
PyModExportFunction *modexport)
|
||||||
|
{
|
||||||
|
*modinit = NULL;
|
||||||
|
*modexport = NULL;
|
||||||
|
|
||||||
const char *name_buf = PyBytes_AS_STRING(info->name_encoded);
|
const char *name_buf = PyBytes_AS_STRING(info->name_encoded);
|
||||||
dl_funcptr exportfunc;
|
dl_funcptr exportfunc;
|
||||||
#ifdef MS_WINDOWS
|
|
||||||
exportfunc = _PyImport_FindSharedFuncptrWindows(
|
|
||||||
info->hook_prefix, name_buf, info->filename, fp);
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
const char *path_buf = PyBytes_AS_STRING(info->filename_encoded);
|
|
||||||
exportfunc = _PyImport_FindSharedFuncptr(
|
|
||||||
info->hook_prefix, name_buf, path_buf, fp);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (exportfunc == NULL) {
|
exportfunc = findfuncptr(
|
||||||
if (!PyErr_Occurred()) {
|
info->hook_prefixes->export_prefix,
|
||||||
PyObject *msg;
|
name_buf, info, fp);
|
||||||
msg = PyUnicode_FromFormat(
|
if (exportfunc) {
|
||||||
"dynamic module does not define "
|
*modexport = (PyModExportFunction)exportfunc;
|
||||||
"module export function (%s_%s)",
|
return 2;
|
||||||
info->hook_prefix, name_buf);
|
}
|
||||||
if (msg != NULL) {
|
|
||||||
PyErr_SetImportError(msg, info->name, info->filename);
|
exportfunc = findfuncptr(
|
||||||
Py_DECREF(msg);
|
info->hook_prefixes->init_prefix,
|
||||||
}
|
name_buf, info, fp);
|
||||||
|
if (exportfunc) {
|
||||||
|
*modinit = (PyModInitFunction)exportfunc;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyErr_Occurred()) {
|
||||||
|
PyObject *msg;
|
||||||
|
msg = PyUnicode_FromFormat(
|
||||||
|
"dynamic module does not define "
|
||||||
|
"module export function (%s_%s or %s_%s)",
|
||||||
|
info->hook_prefixes->export_prefix, name_buf,
|
||||||
|
info->hook_prefixes->init_prefix, name_buf);
|
||||||
|
if (msg != NULL) {
|
||||||
|
PyErr_SetImportError(msg, info->name, info->filename);
|
||||||
|
Py_DECREF(msg);
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
return (PyModInitFunction)exportfunc;
|
|
||||||
}
|
}
|
||||||
#endif /* HAVE_DYNAMIC_LOADING */
|
#endif /* HAVE_DYNAMIC_LOADING */
|
||||||
|
|
||||||
|
|
@ -477,7 +503,7 @@ _PyImport_RunModInitFunc(PyModInitFunction p0,
|
||||||
res.def = (PyModuleDef *)m;
|
res.def = (PyModuleDef *)m;
|
||||||
/* Run PyModule_FromDefAndSpec() to finish loading the module. */
|
/* Run PyModule_FromDefAndSpec() to finish loading the module. */
|
||||||
}
|
}
|
||||||
else if (info->hook_prefix == nonascii_prefix) {
|
else if (info->hook_prefixes == &nonascii_prefixes) {
|
||||||
/* Non-ASCII is only supported for multi-phase init. */
|
/* Non-ASCII is only supported for multi-phase init. */
|
||||||
res.kind = _Py_ext_module_kind_MULTIPHASE;
|
res.kind = _Py_ext_module_kind_MULTIPHASE;
|
||||||
/* Don't allow legacy init for non-ASCII module names. */
|
/* Don't allow legacy init for non-ASCII module names. */
|
||||||
|
|
@ -496,7 +522,7 @@ _PyImport_RunModInitFunc(PyModInitFunction p0,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.def = _PyModule_GetDef(m);
|
res.def = _PyModule_GetDefOrNull(m);
|
||||||
if (res.def == NULL) {
|
if (res.def == NULL) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
_Py_ext_module_loader_result_set_error(
|
_Py_ext_module_loader_result_set_error(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue