Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3daa65a

Browse files
committed
gh-110722: Add PYTHON_PRESITE=package.module to import a module before site.py is run
This is only available --with-pydebug.
1 parent eb50cd3 commit 3daa65a

5 files changed

Lines changed: 95 additions & 0 deletions

File tree

Doc/c-api/init_config.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,7 @@ PyConfig
11001100
11011101
Set by the :option:`-X pycache_prefix=PATH <-X>` command line option and
11021102
the :envvar:`PYTHONPYCACHEPREFIX` environment variable.
1103+
The command-line option takes precedence.
11031104
11041105
If ``NULL``, :data:`sys.pycache_prefix` is set to ``None``.
11051106
@@ -1143,6 +1144,20 @@ PyConfig
11431144
11441145
Default: ``NULL``.
11451146
1147+
.. c:member:: wchar_t* run_presite
1148+
1149+
``package.module`` path to module that should be imported before
1150+
``site.py`` is run.
1151+
1152+
Set by the :option:`-X presite=package.module <-X>` command-line
1153+
option and the :envvar:`PYTHON_PRESITE` environment variable.
1154+
The command-line option takes precedence.
1155+
1156+
Need a :ref:`debug build of Python <debug-build>` (the ``Py_DEBUG`` macro
1157+
must be defined).
1158+
1159+
Default: ``NULL``.
1160+
11461161
.. c:member:: int show_ref_count
11471162
11481163
Show total reference count at exit (excluding immortal objects)?

Include/cpython/initconfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ typedef struct PyConfig {
225225
// If non-zero, turns on statistics gathering.
226226
int _pystats;
227227
#endif
228+
229+
#ifdef Py_DEBUG
230+
// If not empty, import a non-__main__ module before site.py is executed.
231+
// PYTHON_PRESITE=package.module or -X presite=package.module
232+
wchar_t *run_presite;
233+
#endif
228234
} PyConfig;
229235

230236
PyAPI_FUNC(void) PyConfig_InitPythonConfig(PyConfig *config);

Lib/test/test_embed.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
515515
}
516516
if Py_STATS:
517517
CONFIG_COMPAT['_pystats'] = 0
518+
if support.Py_DEBUG:
519+
CONFIG_COMPAT['run_presite'] = None
518520
if MS_WINDOWS:
519521
CONFIG_COMPAT.update({
520522
'legacy_windows_stdio': 0,

Python/initconfig.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
117117
SPEC(_is_python_build, UINT),
118118
#ifdef Py_STATS
119119
SPEC(_pystats, UINT),
120+
#endif
121+
#ifdef Py_DEBUG
122+
SPEC(run_presite, WSTR_OPT),
120123
#endif
121124
{NULL, 0, 0},
122125
};
@@ -241,6 +244,11 @@ The following implementation-specific options are available:\n\
241244
\n\
242245
-X pystats: Enable pystats collection at startup."
243246
#endif
247+
#ifdef Py_DEBUG
248+
"\n\
249+
\n\
250+
-X presite=package.module: import this module before site.py is run."
251+
#endif
244252
;
245253

246254
/* Envvars that don't have equivalent command-line options are listed first */
@@ -790,6 +798,9 @@ PyConfig_Clear(PyConfig *config)
790798
CLEAR(config->run_module);
791799
CLEAR(config->run_filename);
792800
CLEAR(config->check_hash_pycs_mode);
801+
#ifdef Py_DEBUG
802+
CLEAR(config->run_presite);
803+
#endif
793804

794805
_PyWideStringList_Clear(&config->orig_argv);
795806
#undef CLEAR
@@ -1806,6 +1817,36 @@ config_init_pycache_prefix(PyConfig *config)
18061817
}
18071818

18081819

1820+
#ifdef Py_DEBUG
1821+
static PyStatus
1822+
config_init_run_presite(PyConfig *config)
1823+
{
1824+
assert(config->run_presite == NULL);
1825+
1826+
const wchar_t *xoption = config_get_xoption(config, L"presite");
1827+
if (xoption) {
1828+
const wchar_t *sep = wcschr(xoption, L'=');
1829+
if (sep && wcslen(sep) > 1) {
1830+
config->run_presite = _PyMem_RawWcsdup(sep + 1);
1831+
if (config->run_presite == NULL) {
1832+
return _PyStatus_NO_MEMORY();
1833+
}
1834+
}
1835+
else {
1836+
// PYTHON_PRESITE env var ignored
1837+
// if "-X presite=" option is used
1838+
config->run_presite = NULL;
1839+
}
1840+
return _PyStatus_OK();
1841+
}
1842+
1843+
return CONFIG_GET_ENV_DUP(config, &config->run_presite,
1844+
L"PYTHON_PRESITE",
1845+
"PYTHON_PRESITE");
1846+
}
1847+
#endif
1848+
1849+
18091850
static PyStatus
18101851
config_read_complex_options(PyConfig *config)
18111852
{
@@ -1861,6 +1902,16 @@ config_read_complex_options(PyConfig *config)
18611902
return status;
18621903
}
18631904
}
1905+
1906+
#ifdef Py_DEBUG
1907+
if (config->run_presite== NULL) {
1908+
status = config_init_run_presite(config);
1909+
if (_PyStatus_EXCEPTION(status)) {
1910+
return status;
1911+
}
1912+
}
1913+
#endif
1914+
18641915
return _PyStatus_OK();
18651916
}
18661917

Python/pylifecycle.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,27 @@ init_interp_main(PyThreadState *tstate)
11571157
return status;
11581158
}
11591159

1160+
#ifdef Py_DEBUG
1161+
if (config->run_presite) {
1162+
PyObject *presite_modname = PyUnicode_FromWideChar(
1163+
config->run_presite,
1164+
wcslen(config->run_presite)
1165+
);
1166+
if (presite_modname == NULL) {
1167+
fprintf(stderr, "Could not convert module name to unicode\n");
1168+
Py_DECREF(presite_modname);
1169+
}
1170+
else {
1171+
PyObject *presite = PyImport_Import(presite_modname);
1172+
if (presite == NULL) {
1173+
fprintf(stderr, "pre-site import failed; traceback:\n");
1174+
_PyErr_Print(tstate);
1175+
}
1176+
Py_XDECREF(presite);
1177+
}
1178+
}
1179+
#endif
1180+
11601181
status = add_main_module(interp);
11611182
if (_PyStatus_EXCEPTION(status)) {
11621183
return status;

0 commit comments

Comments
 (0)