Skip to content

Commit 6dcb542

Browse files
authored
bpo-36142: Add _PyPreConfig_ReadFromArgv() (GH-12173)
The new function is now responsible to parse -E and -I command line arguments.
1 parent cad1f74 commit 6dcb542

File tree

8 files changed

+209
-52
lines changed

8 files changed

+209
-52
lines changed

Include/internal/pycore_coreconfig.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ PyAPI_FUNC(void) _PyPreConfig_SetGlobalConfig(const _PyPreConfig *config);
4444
PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config);
4545
PyAPI_FUNC(int) _PyPreConfig_AsDict(const _PyPreConfig *config,
4646
PyObject *dict);
47-
47+
PyAPI_FUNC(_PyInitError) _PyPreConfig_ReadFromArgv(_PyPreConfig *config,
48+
const _PyArgv *args);
49+
PyAPI_FUNC(void) _PyPreConfig_Write(const _PyPreConfig *config);
4850

4951

5052
/* --- _PyCoreConfig ---------------------------------------------- */
5153

52-
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config);
5354
PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
5455
PyAPI_FUNC(int) _PyCoreConfig_Copy(
5556
_PyCoreConfig *config,
@@ -67,8 +68,11 @@ PyAPI_FUNC(int) _PyCoreConfig_GetEnvDup(
6768
wchar_t **dest,
6869
wchar_t *wname,
6970
char *name);
71+
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config,
72+
const _PyPreConfig *preconfig);
7073
PyAPI_FUNC(_PyInitError) _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config,
71-
const _PyArgv *args);
74+
const _PyArgv *args,
75+
const _PyPreConfig *preconfig);
7276
PyAPI_FUNC(void) _PyCoreConfig_Write(const _PyCoreConfig *config);
7377

7478
#ifdef __cplusplus

Include/internal/pycore_getopt.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ typedef struct {
1717
int val;
1818
} _PyOS_LongOption;
1919

20-
extern int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring,
21-
const _PyOS_LongOption *longopts, int *longindex);
20+
extern int _PyOS_GetOpt(int argc, wchar_t **argv, int *longindex);
2221

2322
#endif /* !Py_INTERNAL_PYGETOPT_H */

Modules/main.c

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,20 +286,32 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config,
286286

287287
/* --- pymain_init() ---------------------------------------------- */
288288

289-
static void
290-
config_clear(_PyCoreConfig *config)
289+
static _PyInitError
290+
preconfig_read_write(_PyPreConfig *config, const _PyArgv *args)
291291
{
292+
_PyInitError err;
293+
292294
PyMemAllocatorEx old_alloc;
293295
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
294296

295-
_PyCoreConfig_Clear(config);
297+
_PyPreConfig_GetGlobalConfig(config);
298+
299+
err = _PyPreConfig_ReadFromArgv(config, args);
296300

297301
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
302+
303+
if (_Py_INIT_FAILED(err)) {
304+
return err;
305+
}
306+
307+
_PyPreConfig_Write(config);
308+
return _Py_INIT_OK();
298309
}
299310

300311

301312
static _PyInitError
302-
config_read_write(_PyCoreConfig *config, const _PyArgv *args)
313+
config_read_write(_PyCoreConfig *config, const _PyArgv *args,
314+
const _PyPreConfig *preconfig)
303315
{
304316
_PyInitError err;
305317

@@ -308,7 +320,7 @@ config_read_write(_PyCoreConfig *config, const _PyArgv *args)
308320

309321
_PyCoreConfig_GetGlobalConfig(config);
310322

311-
err = _PyCoreConfig_ReadFromArgv(config, args);
323+
err = _PyCoreConfig_ReadFromArgv(config, args, preconfig);
312324

313325
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
314326

@@ -344,6 +356,7 @@ static _PyInitError
344356
pymain_init(const _PyArgv *args, PyInterpreterState **interp_p)
345357
{
346358
_PyInitError err;
359+
PyMemAllocatorEx old_alloc;
347360

348361
err = _PyRuntime_Initialize();
349362
if (_Py_INIT_FAILED(err)) {
@@ -359,10 +372,18 @@ pymain_init(const _PyArgv *args, PyInterpreterState **interp_p)
359372
fedisableexcept(FE_OVERFLOW);
360373
#endif
361374

375+
_PyPreConfig local_preconfig = _PyPreConfig_INIT;
376+
_PyPreConfig *preconfig = &local_preconfig;
377+
362378
_PyCoreConfig local_config = _PyCoreConfig_INIT;
363379
_PyCoreConfig *config = &local_config;
364380

365-
err = config_read_write(config, args);
381+
err = preconfig_read_write(preconfig, args);
382+
if (_Py_INIT_FAILED(err)) {
383+
goto done;
384+
}
385+
386+
err = config_read_write(config, args, preconfig);
366387
if (_Py_INIT_FAILED(err)) {
367388
goto done;
368389
}
@@ -382,7 +403,12 @@ pymain_init(const _PyArgv *args, PyInterpreterState **interp_p)
382403
err = _Py_INIT_OK();
383404

384405
done:
385-
config_clear(config);
406+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
407+
408+
_PyPreConfig_Clear(preconfig);
409+
_PyCoreConfig_Clear(config);
410+
411+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
386412
return err;
387413
}
388414

Python/coreconfig.c

Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@
2323

2424
/* --- Command line options --------------------------------------- */
2525

26-
#define PROGRAM_OPTS L"bBc:dEhiIJm:OqRsStuvVW:xX:?"
27-
28-
static const _PyOS_LongOption longoptions[] = {
29-
{L"check-hash-based-pycs", 1, 0},
30-
{NULL, 0, 0},
31-
};
32-
3326
/* Short usage message (with %s for argv0) */
3427
static const char usage_line[] =
3528
"usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
@@ -1483,28 +1476,61 @@ config_init_fs_encoding(_PyCoreConfig *config)
14831476
}
14841477

14851478

1486-
/* Read configuration settings from standard locations
1487-
*
1488-
* This function doesn't make any changes to the interpreter state - it
1489-
* merely populates any missing configuration settings. This allows an
1490-
* embedding application to completely override a config option by
1491-
* setting it before calling this function, or else modify the default
1492-
* setting before passing the fully populated config to Py_EndInitialization.
1493-
*
1494-
* More advanced selective initialization tricks are possible by calling
1495-
* this function multiple times with various preconfigured settings.
1496-
*/
1479+
static _PyInitError
1480+
_PyCoreConfig_ReadPreConfig(_PyCoreConfig *config)
1481+
{
1482+
_PyInitError err;
1483+
_PyPreConfig local_preconfig = _PyPreConfig_INIT;
1484+
_PyPreConfig_GetGlobalConfig(&local_preconfig);
1485+
1486+
if (_PyPreConfig_Copy(&local_preconfig, &config->preconfig) < 0) {
1487+
err = _Py_INIT_NO_MEMORY();
1488+
goto done;
1489+
}
1490+
1491+
err = _PyPreConfig_Read(&local_preconfig);
1492+
if (_Py_INIT_FAILED(err)) {
1493+
goto done;
1494+
}
1495+
1496+
if (_PyPreConfig_Copy(&config->preconfig, &local_preconfig) < 0) {
1497+
err = _Py_INIT_NO_MEMORY();
1498+
goto done;
1499+
}
1500+
err = _Py_INIT_OK();
1501+
1502+
done:
1503+
_PyPreConfig_Clear(&local_preconfig);
1504+
return err;
1505+
}
1506+
1507+
1508+
/* Read the configuration into _PyCoreConfig and initialize the LC_CTYPE
1509+
locale: enable UTF-8 mode (PEP 540) and/or coerce the C locale (PEP 538).
14971510
1511+
Read the configuration from:
1512+
1513+
* Environment variables
1514+
* Py_xxx global configuration variables
1515+
1516+
See _PyCoreConfig_ReadFromArgv() to parse also command line arguments. */
14981517
_PyInitError
1499-
_PyCoreConfig_Read(_PyCoreConfig *config)
1518+
_PyCoreConfig_Read(_PyCoreConfig *config, const _PyPreConfig *preconfig)
15001519
{
15011520
_PyInitError err;
15021521

15031522
_PyCoreConfig_GetGlobalConfig(config);
15041523

1505-
err = _PyPreConfig_Read(&config->preconfig);
1506-
if (_Py_INIT_FAILED(err)) {
1507-
return err;
1524+
if (preconfig != NULL) {
1525+
if (_PyPreConfig_Copy(&config->preconfig, preconfig) < 0) {
1526+
return _Py_INIT_NO_MEMORY();
1527+
}
1528+
}
1529+
else {
1530+
err = _PyCoreConfig_ReadPreConfig(config);
1531+
if (_Py_INIT_FAILED(err)) {
1532+
return err;
1533+
}
15081534
}
15091535

15101536
assert(config->preconfig.use_environment >= 0);
@@ -1851,8 +1877,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
18511877
_PyOS_ResetGetOpt();
18521878
do {
18531879
int longindex = -1;
1854-
int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, PROGRAM_OPTS,
1855-
longoptions, &longindex);
1880+
int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, &longindex);
18561881
if (c == EOF) {
18571882
break;
18581883
}
@@ -1915,8 +1940,9 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
19151940
config->interactive++;
19161941
break;
19171942

1943+
case 'E':
19181944
case 'I':
1919-
config->preconfig.isolated++;
1945+
/* option handled by _PyPreConfig_ReadFromArgv() */
19201946
break;
19211947

19221948
/* case 'J': reserved for Jython */
@@ -1937,10 +1963,6 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
19371963
config->site_import = 0;
19381964
break;
19391965

1940-
case 'E':
1941-
config->preconfig.use_environment = 0;
1942-
break;
1943-
19441966
case 't':
19451967
/* ignored for backwards compatibility */
19461968
break;
@@ -2235,7 +2257,8 @@ config_usage(int error, const wchar_t* program)
22352257

22362258
/* Parse command line options and environment variables. */
22372259
static _PyInitError
2238-
config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline)
2260+
config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
2261+
const _PyPreConfig *preconfig)
22392262
{
22402263
int need_usage = 0;
22412264
_PyInitError err;
@@ -2271,7 +2294,7 @@ config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline)
22712294
return err;
22722295
}
22732296

2274-
err = _PyCoreConfig_Read(config);
2297+
err = _PyCoreConfig_Read(config, preconfig);
22752298
if (_Py_INIT_FAILED(err)) {
22762299
return err;
22772300
}
@@ -2296,7 +2319,8 @@ config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline)
22962319

22972320

22982321
static _PyInitError
2299-
config_read_from_argv_impl(_PyCoreConfig *config, const _PyArgv *args)
2322+
config_read_from_argv_impl(_PyCoreConfig *config, const _PyArgv *args,
2323+
const _PyPreConfig *preconfig)
23002324
{
23012325
_PyInitError err;
23022326

@@ -2309,7 +2333,7 @@ config_read_from_argv_impl(_PyCoreConfig *config, const _PyArgv *args)
23092333
goto done;
23102334
}
23112335

2312-
err = config_from_cmdline(config, &cmdline);
2336+
err = config_from_cmdline(config, &cmdline, preconfig);
23132337
if (_Py_INIT_FAILED(err)) {
23142338
goto done;
23152339
}
@@ -2330,7 +2354,8 @@ config_read_from_argv_impl(_PyCoreConfig *config, const _PyArgv *args)
23302354
* Environment variables
23312355
* Py_xxx global configuration variables */
23322356
_PyInitError
2333-
_PyCoreConfig_ReadFromArgv(_PyCoreConfig *config, const _PyArgv *args)
2357+
_PyCoreConfig_ReadFromArgv(_PyCoreConfig *config, const _PyArgv *args,
2358+
const _PyPreConfig *preconfig)
23342359
{
23352360
_PyInitError err;
23362361
int init_utf8_mode = Py_UTF8Mode;
@@ -2381,7 +2406,7 @@ _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config, const _PyArgv *args)
23812406
Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
23822407
#endif
23832408

2384-
err = config_read_from_argv_impl(config, args);
2409+
err = config_read_from_argv_impl(config, args, preconfig);
23852410
if (_Py_INIT_FAILED(err)) {
23862411
goto done;
23872412
}

Python/getopt.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ wchar_t *_PyOS_optarg = NULL; /* optional argument */
4343

4444
static wchar_t *opt_ptr = L"";
4545

46+
/* Python command line short and long options */
47+
48+
#define SHORT_OPTS L"bBc:dEhiIJm:OqRsStuvVW:xX:?"
49+
50+
static const _PyOS_LongOption longopts[] = {
51+
{L"check-hash-based-pycs", 1, 0},
52+
{NULL, 0, 0},
53+
};
54+
55+
4656
void _PyOS_ResetGetOpt(void)
4757
{
4858
_PyOS_opterr = 1;
@@ -51,8 +61,7 @@ void _PyOS_ResetGetOpt(void)
5161
opt_ptr = L"";
5262
}
5363

54-
int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring,
55-
const _PyOS_LongOption *longopts, int *longindex)
64+
int _PyOS_GetOpt(int argc, wchar_t **argv, int *longindex)
5665
{
5766
wchar_t *ptr;
5867
wchar_t option;
@@ -128,7 +137,7 @@ int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring,
128137
return '_';
129138
}
130139

131-
if ((ptr = wcschr(optstring, option)) == NULL) {
140+
if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) {
132141
if (_PyOS_opterr)
133142
fprintf(stderr, "Unknown option: -%c\n", (char)option);
134143
return '_';

Python/pathconfig.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ pathconfig_global_init(void)
393393
_PyInitError err;
394394
_PyCoreConfig config = _PyCoreConfig_INIT;
395395

396-
err = _PyCoreConfig_Read(&config);
396+
err = _PyCoreConfig_Read(&config, NULL);
397397
if (_Py_INIT_FAILED(err)) {
398398
goto error;
399399
}

0 commit comments

Comments
 (0)