Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit84b7e9e

Browse files
authored
gh-110722: Add PYTHON_PRESITE to import a module before site.py is run (#110769)
1 parentab08ff7 commit84b7e9e

File tree

8 files changed

+178
-7
lines changed

8 files changed

+178
-7
lines changed

‎Doc/c-api/init_config.rst

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ PyConfig
716716
717717
Set to ``1`` by the :envvar:`PYTHONDUMPREFS` environment variable.
718718
719-
Need a special build of Python with the ``Py_TRACE_REFS`` macro defined:
719+
Needs a special build of Python with the ``Py_TRACE_REFS`` macro defined:
720720
see the :option:`configure --with-trace-refs option <--with-trace-refs>`.
721721
722722
Default: ``0``.
@@ -1048,7 +1048,7 @@ PyConfig
10481048
Incremented by the :option:`-d` command line option. Set to the
10491049
:envvar:`PYTHONDEBUG` environment variable value.
10501050
1051-
Need a :ref:`debug build of Python <debug-build>` (the ``Py_DEBUG`` macro
1051+
Needs a :ref:`debug build of Python <debug-build>` (the ``Py_DEBUG`` macro
10521052
must be defined).
10531053
10541054
Default: ``0``.
@@ -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,13 +1144,27 @@ 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+
Needs 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)?
11491164
11501165
Set to ``1`` by :option:`-X showrefcount <-X>` command line option.
11511166
1152-
Need a :ref:`debug build of Python <debug-build>` (the ``Py_REF_DEBUG``
1167+
Needs a :ref:`debug build of Python <debug-build>` (the ``Py_REF_DEBUG``
11531168
macro must be defined).
11541169
11551170
Default: ``0``.

‎Doc/using/cmdline.rst

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,12 @@ Miscellaneous options
552552
This option may be useful for users who need to limit CPU resources of a
553553
container system. See also:envvar:`PYTHON_CPU_COUNT`.
554554
If *n* is ``default``, nothing is overridden.
555+
*:samp:`-X presite={package.module}` specifies a module that should be
556+
imported before the:mod:`site` module is executed and before the
557+
:mod:`__main__` module exists. Therefore, the imported module isn't
558+
:mod:`__main__`. This can be used to execute code early during Python
559+
initialization. Python needs to be:ref:`built in debug mode<debug-build>`
560+
for this option to exist. See also:envvar:`PYTHON_PRESITE`.
555561

556562
It also allows passing arbitrary values and retrieving them through the
557563
:data:`sys._xoptions` dictionary.
@@ -602,6 +608,9 @@ Miscellaneous options
602608
..versionadded::3.13
603609
The ``-X cpu_count`` option.
604610

611+
..versionadded::3.13
612+
The ``-X presite`` option.
613+
605614

606615
Options you shouldn't use
607616
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1091,13 +1100,33 @@ Debug-mode variables
10911100
If set, Python will dump objects and reference counts still alive after
10921101
shutting down the interpreter.
10931102

1094-
Need Python configured with the:option:`--with-trace-refs` build option.
1103+
Needs Python configured with the:option:`--with-trace-refs` build option.
10951104

1096-
..envvar::PYTHONDUMPREFSFILE=FILENAME
1105+
..envvar::PYTHONDUMPREFSFILE
10971106

10981107
If set, Python will dump objects and reference counts still alive
1099-
after shutting down the interpreter into a file called *FILENAME*.
1108+
after shutting down the interpreter into a file under the path given
1109+
as the value to this environment variable.
11001110

1101-
Need Python configured with the:option:`--with-trace-refs` build option.
1111+
Needs Python configured with the:option:`--with-trace-refs` build option.
11021112

11031113
..versionadded::3.11
1114+
1115+
..envvar::PYTHON_PRESITE
1116+
1117+
If this variable is set to a module, that module will be imported
1118+
early in the interpreter lifecycle, before the:mod:`site` module is
1119+
executed, and before the:mod:`__main__` module is created.
1120+
Therefore, the imported module is not treated as:mod:`__main__`.
1121+
1122+
This can be used to execute code early during Python initialization.
1123+
1124+
To import a submodule, use ``package.module`` as the value, like in
1125+
an import statement.
1126+
1127+
See also the:option:`-X presite <-X>` command-line option,
1128+
which takes precedence over this variable.
1129+
1130+
Needs Python configured with the:option:`--with-pydebug` build option.
1131+
1132+
..versionadded::3.13

‎Doc/whatsnew/3.13.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,3 +1356,13 @@ removed, although there is currently no date scheduled for their removal.
13561356

13571357
* Remove undocumented ``PY_TIMEOUT_MAX`` constant from the limited C API.
13581358
(Contributed by Victor Stinner in:gh:`110014`.)
1359+
1360+
1361+
Regression Test Changes
1362+
=======================
1363+
1364+
* Python built with:file:`configure`:option:`--with-pydebug` now
1365+
supports a:option:`-X presite=package.module <-X>` command-line
1366+
option. If used, it specifies a module that should be imported early
1367+
in the lifecycle of the interpreter, before ``site.py`` is executed.
1368+
(Contributed by Łukasz Langa in:gh:`110769`.)

‎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+
#ifdefPy_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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
515515
}
516516
ifPy_STATS:
517517
CONFIG_COMPAT['_pystats']=0
518+
ifsupport.Py_DEBUG:
519+
CONFIG_COMPAT['run_presite']=None
518520
ifMS_WINDOWS:
519521
CONFIG_COMPAT.update({
520522
'legacy_windows_stdio':0,
@@ -1818,6 +1820,22 @@ def test_no_memleak(self):
18181820
self.assertEqual(refs,0,out)
18191821
self.assertEqual(blocks,0,out)
18201822

1823+
@unittest.skipUnless(support.Py_DEBUG,
1824+
'-X presite requires a Python debug build')
1825+
deftest_presite(self):
1826+
cmd= [sys.executable,"-I","-X","presite=test.reperf","-c","print('cmd')"]
1827+
proc=subprocess.run(
1828+
cmd,
1829+
stdout=subprocess.PIPE,
1830+
stderr=subprocess.STDOUT,
1831+
text=True,
1832+
)
1833+
self.assertEqual(proc.returncode,0)
1834+
out=proc.stdout.strip()
1835+
self.assertIn("10 times sub",out)
1836+
self.assertIn("CPU seconds",out)
1837+
self.assertIn("cmd",out)
1838+
18211839

18221840
classStdPrinterTests(EmbeddingTestsMixin,unittest.TestCase):
18231841
# Test PyStdPrinter_Type which is used by _PySys_SetPreliminaryStderr():
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add:envvar:`PYTHON_PRESITE=package.module` to import a module early in the
2+
interpreter lifecycle before ``site.py`` is executed. Python needs to be
3+
:ref:`built in debug mode<debug-build>` for this option to exist.

‎Python/initconfig.c

Lines changed: 54 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
#ifdefPy_STATS
119119
SPEC(_pystats,UINT),
120+
#endif
121+
#ifdefPy_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+
#ifdefPy_DEBUG
248+
"\n\
249+
\n\
250+
-Xpresite=package.module:importthismodulebeforesite.pyisrun."
251+
#endif
244252
;
245253

246254
/* Envvars that don't have equivalent command-line options are listed first */
@@ -297,6 +305,9 @@ static const char usage_envvars[] =
297305
#ifdefPy_STATS
298306
"PYTHONSTATS : turns on statistics gathering\n"
299307
#endif
308+
#ifdefPy_DEBUG
309+
"PYTHON_PRESITE=pkg.mod : import this module before site.py is run\n"
310+
#endif
300311
;
301312

302313
#if defined(MS_WINDOWS)
@@ -790,6 +801,9 @@ PyConfig_Clear(PyConfig *config)
790801
CLEAR(config->run_module);
791802
CLEAR(config->run_filename);
792803
CLEAR(config->check_hash_pycs_mode);
804+
#ifdefPy_DEBUG
805+
CLEAR(config->run_presite);
806+
#endif
793807

794808
_PyWideStringList_Clear(&config->orig_argv);
795809
#undef CLEAR
@@ -1806,6 +1820,36 @@ config_init_pycache_prefix(PyConfig *config)
18061820
}
18071821

18081822

1823+
#ifdefPy_DEBUG
1824+
staticPyStatus
1825+
config_init_run_presite(PyConfig*config)
1826+
{
1827+
assert(config->run_presite==NULL);
1828+
1829+
constwchar_t*xoption=config_get_xoption(config,L"presite");
1830+
if (xoption) {
1831+
constwchar_t*sep=wcschr(xoption,L'=');
1832+
if (sep&&wcslen(sep)>1) {
1833+
config->run_presite=_PyMem_RawWcsdup(sep+1);
1834+
if (config->run_presite==NULL) {
1835+
return_PyStatus_NO_MEMORY();
1836+
}
1837+
}
1838+
else {
1839+
// PYTHON_PRESITE env var ignored
1840+
// if "-X presite=" option is used
1841+
config->run_presite=NULL;
1842+
}
1843+
return_PyStatus_OK();
1844+
}
1845+
1846+
returnCONFIG_GET_ENV_DUP(config,&config->run_presite,
1847+
L"PYTHON_PRESITE",
1848+
"PYTHON_PRESITE");
1849+
}
1850+
#endif
1851+
1852+
18091853
staticPyStatus
18101854
config_read_complex_options(PyConfig*config)
18111855
{
@@ -1861,6 +1905,16 @@ config_read_complex_options(PyConfig *config)
18611905
returnstatus;
18621906
}
18631907
}
1908+
1909+
#ifdefPy_DEBUG
1910+
if (config->run_presite==NULL) {
1911+
status=config_init_run_presite(config);
1912+
if (_PyStatus_EXCEPTION(status)) {
1913+
returnstatus;
1914+
}
1915+
}
1916+
#endif
1917+
18641918
return_PyStatus_OK();
18651919
}
18661920

‎Python/pylifecycle.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,38 @@ pyinit_main_reconfigure(PyThreadState *tstate)
10761076
}
10771077

10781078

1079+
#ifdefPy_DEBUG
1080+
staticvoid
1081+
run_presite(PyThreadState*tstate)
1082+
{
1083+
PyInterpreterState*interp=tstate->interp;
1084+
constPyConfig*config=_PyInterpreterState_GetConfig(interp);
1085+
1086+
if (!config->run_presite) {
1087+
return;
1088+
}
1089+
1090+
PyObject*presite_modname=PyUnicode_FromWideChar(
1091+
config->run_presite,
1092+
wcslen(config->run_presite)
1093+
);
1094+
if (presite_modname==NULL) {
1095+
fprintf(stderr,"Could not convert pre-site module name to unicode\n");
1096+
Py_DECREF(presite_modname);
1097+
}
1098+
else {
1099+
PyObject*presite=PyImport_Import(presite_modname);
1100+
if (presite==NULL) {
1101+
fprintf(stderr,"pre-site import failed:\n");
1102+
_PyErr_Print(tstate);
1103+
}
1104+
Py_XDECREF(presite);
1105+
Py_DECREF(presite_modname);
1106+
}
1107+
}
1108+
#endif
1109+
1110+
10791111
staticPyStatus
10801112
init_interp_main(PyThreadState*tstate)
10811113
{
@@ -1157,6 +1189,10 @@ init_interp_main(PyThreadState *tstate)
11571189
returnstatus;
11581190
}
11591191

1192+
#ifdefPy_DEBUG
1193+
run_presite(tstate);
1194+
#endif
1195+
11601196
status=add_main_module(interp);
11611197
if (_PyStatus_EXCEPTION(status)) {
11621198
returnstatus;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp