@@ -296,13 +296,16 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
296
296
})
297
297
PYTHON_PRE_CONFIG = dict (DEFAULT_PRE_CONFIG ,
298
298
parse_argv = 1 ,
299
+ coerce_c_locale = GET_DEFAULT_CONFIG ,
300
+ utf8_mode = GET_DEFAULT_CONFIG ,
299
301
)
300
302
ISOLATED_PRE_CONFIG = dict (DEFAULT_PRE_CONFIG ,
301
303
configure_locale = 0 ,
302
304
isolated = 1 ,
303
305
use_environment = 0 ,
304
306
utf8_mode = 0 ,
305
307
dev_mode = 0 ,
308
+ coerce_c_locale = 0 ,
306
309
)
307
310
308
311
COPY_PRE_CONFIG = [
@@ -435,6 +438,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
435
438
('Py_LegacyWindowsStdioFlag' , 'legacy_windows_stdio' ),
436
439
))
437
440
441
+ EXPECTED_CONFIG = None
442
+
438
443
def main_xoptions (self , xoptions_list ):
439
444
xoptions = {}
440
445
for opt in xoptions_list :
@@ -445,37 +450,15 @@ def main_xoptions(self, xoptions_list):
445
450
xoptions [opt ] = True
446
451
return xoptions
447
452
448
- def get_expected_config (self , expected_preconfig , expected , env , api ,
449
- add_path = None ):
450
- if api == CONFIG_INIT_PYTHON :
451
- default_config = self .PYTHON_CORE_CONFIG
452
- elif api == CONFIG_INIT_ISOLATED :
453
- default_config = self .ISOLATED_CORE_CONFIG
454
- else :
455
- default_config = self .DEFAULT_CORE_CONFIG
456
- expected = dict (default_config , ** expected )
457
- expected ['_config_init' ] = api
458
-
453
+ def _get_expected_config (self , env ):
459
454
code = textwrap .dedent ('''
460
455
import json
461
456
import sys
462
457
import _testinternalcapi
463
458
464
459
configs = _testinternalcapi.get_configs()
465
- core_config = configs['core_config']
466
- data = {
467
- 'stdio_encoding': sys.stdout.encoding,
468
- 'stdio_errors': sys.stdout.errors,
469
- 'prefix': sys.prefix,
470
- 'base_prefix': sys.base_prefix,
471
- 'exec_prefix': sys.exec_prefix,
472
- 'base_exec_prefix': sys.base_exec_prefix,
473
- 'filesystem_encoding': sys.getfilesystemencoding(),
474
- 'filesystem_errors': sys.getfilesystemencodeerrors(),
475
- 'module_search_paths': core_config['module_search_paths'],
476
- }
477
-
478
- data = json.dumps(data)
460
+
461
+ data = json.dumps(configs)
479
462
data = data.encode('utf-8')
480
463
sys.stdout.buffer.write(data)
481
464
sys.stdout.buffer.flush()
@@ -484,10 +467,6 @@ def get_expected_config(self, expected_preconfig, expected, env, api,
484
467
# Use -S to not import the site module: get the proper configuration
485
468
# when test_embed is run from a venv (bpo-35313)
486
469
args = [sys .executable , '-S' , '-c' , code ]
487
- env = dict (env )
488
- if not expected ['isolated' ]:
489
- env ['PYTHONCOERCECLOCALE' ] = '0'
490
- env ['PYTHONUTF8' ] = '0'
491
470
proc = subprocess .run (args , env = env ,
492
471
stdout = subprocess .PIPE ,
493
472
stderr = subprocess .STDOUT )
@@ -496,10 +475,46 @@ def get_expected_config(self, expected_preconfig, expected, env, api,
496
475
f"stdout={ proc .stdout !r} stderr={ proc .stderr !r} " )
497
476
stdout = proc .stdout .decode ('utf-8' )
498
477
try :
499
- config = json .loads (stdout )
478
+ return json .loads (stdout )
500
479
except json .JSONDecodeError :
501
480
self .fail (f"fail to decode stdout: { stdout !r} " )
502
481
482
+ def get_expected_config (self , expected_preconfig , expected , env , api ,
483
+ add_path = None ):
484
+ cls = self .__class__
485
+ if cls .EXPECTED_CONFIG is None :
486
+ cls .EXPECTED_CONFIG = self ._get_expected_config (env )
487
+ configs = {key : dict (value )
488
+ for key , value in self .EXPECTED_CONFIG .items ()}
489
+
490
+ pre_config = configs ['pre_config' ]
491
+ for key , value in expected_preconfig .items ():
492
+ if value is self .GET_DEFAULT_CONFIG :
493
+ expected_preconfig [key ] = pre_config [key ]
494
+
495
+ if not expected_preconfig ['configure_locale' ] or api == CONFIG_INIT :
496
+ # there is no easy way to get the locale encoding before
497
+ # setlocale(LC_CTYPE, "") is called: don't test encodings
498
+ for key in ('filesystem_encoding' , 'filesystem_errors' ,
499
+ 'stdio_encoding' , 'stdio_errors' ):
500
+ expected [key ] = self .IGNORE_CONFIG
501
+
502
+ if not expected_preconfig ['configure_locale' ]:
503
+ # UTF-8 Mode depends on the locale. There is no easy way
504
+ # to guess if UTF-8 Mode will be enabled or not if the locale
505
+ # is not configured.
506
+ expected_preconfig ['utf8_mode' ] = self .IGNORE_CONFIG
507
+
508
+ if expected_preconfig ['utf8_mode' ] == 1 :
509
+ if expected ['filesystem_encoding' ] is self .GET_DEFAULT_CONFIG :
510
+ expected ['filesystem_encoding' ] = 'utf-8'
511
+ if expected ['filesystem_errors' ] is self .GET_DEFAULT_CONFIG :
512
+ expected ['filesystem_errors' ] = self .UTF8_MODE_ERRORS
513
+ if expected ['stdio_encoding' ] is self .GET_DEFAULT_CONFIG :
514
+ expected ['stdio_encoding' ] = 'utf-8'
515
+ if expected ['stdio_errors' ] is self .GET_DEFAULT_CONFIG :
516
+ expected ['stdio_errors' ] = 'surrogateescape'
517
+
503
518
if expected ['executable' ] is self .GET_DEFAULT_CONFIG :
504
519
if sys .platform == 'win32' :
505
520
expected ['executable' ] = self .test_exe
@@ -511,24 +526,28 @@ def get_expected_config(self, expected_preconfig, expected, env, api,
511
526
if expected ['program_name' ] is self .GET_DEFAULT_CONFIG :
512
527
expected ['program_name' ] = './_testembed'
513
528
529
+ core_config = configs ['core_config' ]
514
530
for key , value in expected .items ():
515
531
if value is self .GET_DEFAULT_CONFIG :
516
- expected [key ] = config [key ]
532
+ expected [key ] = core_config [key ]
517
533
534
+ prepend_path = expected ['module_search_path_env' ]
535
+ if prepend_path is not None :
536
+ expected ['module_search_paths' ] = [prepend_path , * expected ['module_search_paths' ]]
518
537
if add_path is not None :
519
- expected ['module_search_paths' ].append (add_path )
520
-
521
- if not expected_preconfig ['configure_locale' ]:
522
- # there is no easy way to get the locale encoding before
523
- # setlocale(LC_CTYPE, "") is called: don't test encodings
524
- for key in ('filesystem_encoding' , 'filesystem_errors' ,
525
- 'stdio_encoding' , 'stdio_errors' ):
526
- expected [key ] = self .IGNORE_CONFIG
538
+ expected ['module_search_paths' ] = [* expected ['module_search_paths' ], add_path ]
527
539
528
- return expected
540
+ for key in self .COPY_PRE_CONFIG :
541
+ if key not in expected_preconfig :
542
+ expected_preconfig [key ] = expected [key ]
529
543
530
544
def check_pre_config (self , config , expected ):
531
- self .assertEqual (config ['pre_config' ], expected )
545
+ pre_config = dict (config ['pre_config' ])
546
+ for key , value in list (expected .items ()):
547
+ if value is self .IGNORE_CONFIG :
548
+ del pre_config [key ]
549
+ del expected [key ]
550
+ self .assertEqual (pre_config , expected )
532
551
533
552
def check_core_config (self , config , expected ):
534
553
core_config = dict (config ['core_config' ])
@@ -567,10 +586,6 @@ def check_config(self, testname, expected_config=None, expected_preconfig=None,
567
586
for key in list (env ):
568
587
if key .startswith ('PYTHON' ):
569
588
del env [key ]
570
- # Disable C locale coercion and UTF-8 mode to not depend
571
- # on the current locale
572
- env ['PYTHONCOERCECLOCALE' ] = '0'
573
- env ['PYTHONUTF8' ] = '0'
574
589
575
590
if api == CONFIG_INIT_ISOLATED :
576
591
default_preconfig = self .ISOLATED_PRE_CONFIG
@@ -583,12 +598,19 @@ def check_config(self, testname, expected_config=None, expected_preconfig=None,
583
598
expected_preconfig = dict (default_preconfig , ** expected_preconfig )
584
599
if expected_config is None :
585
600
expected_config = {}
586
- expected_config = self .get_expected_config (expected_preconfig ,
587
- expected_config , env ,
588
- api , add_path )
589
- for key in self .COPY_PRE_CONFIG :
590
- if key not in expected_preconfig :
591
- expected_preconfig [key ] = expected_config [key ]
601
+
602
+ if api == CONFIG_INIT_PYTHON :
603
+ default_config = self .PYTHON_CORE_CONFIG
604
+ elif api == CONFIG_INIT_ISOLATED :
605
+ default_config = self .ISOLATED_CORE_CONFIG
606
+ else :
607
+ default_config = self .DEFAULT_CORE_CONFIG
608
+ expected_config = dict (default_config , ** expected_config )
609
+ expected_config ['_config_init' ] = api
610
+
611
+ self .get_expected_config (expected_preconfig ,
612
+ expected_config , env ,
613
+ api , add_path )
592
614
593
615
out , err = self .run_embedded_interpreter (testname , env = env )
594
616
if stderr is None and not expected_config ['verbose' ]:
@@ -624,10 +646,6 @@ def test_init_global_config(self):
624
646
'quiet' : 1 ,
625
647
'buffered_stdio' : 0 ,
626
648
627
- 'stdio_encoding' : 'utf-8' ,
628
- 'stdio_errors' : 'surrogateescape' ,
629
- 'filesystem_encoding' : 'utf-8' ,
630
- 'filesystem_errors' : self .UTF8_MODE_ERRORS ,
631
649
'user_site_directory' : 0 ,
632
650
'pathconfig_warnings' : 0 ,
633
651
}
@@ -650,8 +668,6 @@ def test_init_from_config(self):
650
668
651
669
'stdio_encoding' : 'iso8859-1' ,
652
670
'stdio_errors' : 'replace' ,
653
- 'filesystem_encoding' : 'utf-8' ,
654
- 'filesystem_errors' : self .UTF8_MODE_ERRORS ,
655
671
656
672
'pycache_prefix' : 'conf_pycache_prefix' ,
657
673
'program_name' : './conf_program_name' ,
@@ -679,43 +695,42 @@ def test_init_from_config(self):
679
695
}
680
696
self .check_config ("init_from_config" , config , preconfig )
681
697
682
- INIT_ENV_PRECONFIG = {
683
- 'allocator' : PYMEM_ALLOCATOR_MALLOC ,
684
- }
685
- INIT_ENV_CONFIG = {
686
- 'use_hash_seed' : 1 ,
687
- 'hash_seed' : 42 ,
688
- 'tracemalloc' : 2 ,
689
- 'import_time' : 1 ,
690
- 'malloc_stats' : 1 ,
691
- 'inspect' : 1 ,
692
- 'optimization_level' : 2 ,
693
- 'pycache_prefix' : 'env_pycache_prefix' ,
694
- 'write_bytecode' : 0 ,
695
- 'verbose' : 1 ,
696
- 'buffered_stdio' : 0 ,
697
- 'stdio_encoding' : 'iso8859-1' ,
698
- 'stdio_errors' : 'replace' ,
699
- 'user_site_directory' : 0 ,
700
- 'faulthandler' : 1 ,
701
- }
702
-
703
698
def test_init_env (self ):
704
- self .check_config ("init_env" , self .INIT_ENV_CONFIG , self .INIT_ENV_PRECONFIG )
699
+ preconfig = {
700
+ 'allocator' : PYMEM_ALLOCATOR_MALLOC ,
701
+ }
702
+ config = {
703
+ 'use_hash_seed' : 1 ,
704
+ 'hash_seed' : 42 ,
705
+ 'tracemalloc' : 2 ,
706
+ 'import_time' : 1 ,
707
+ 'malloc_stats' : 1 ,
708
+ 'inspect' : 1 ,
709
+ 'optimization_level' : 2 ,
710
+ 'module_search_path_env' : '/my/path' ,
711
+ 'pycache_prefix' : 'env_pycache_prefix' ,
712
+ 'write_bytecode' : 0 ,
713
+ 'verbose' : 1 ,
714
+ 'buffered_stdio' : 0 ,
715
+ 'stdio_encoding' : 'iso8859-1' ,
716
+ 'stdio_errors' : 'replace' ,
717
+ 'user_site_directory' : 0 ,
718
+ 'faulthandler' : 1 ,
719
+ 'warnoptions' : ['EnvVar' ],
720
+ }
721
+ self .check_config ("init_env" , config , preconfig )
705
722
706
723
def test_init_env_dev_mode (self ):
707
- preconfig = dict (self .INIT_ENV_PRECONFIG ,
708
- allocator = PYMEM_ALLOCATOR_DEBUG )
709
- config = dict (self .INIT_ENV_CONFIG ,
710
- dev_mode = 1 ,
724
+ preconfig = dict (allocator = PYMEM_ALLOCATOR_DEBUG )
725
+ config = dict (dev_mode = 1 ,
726
+ faulthandler = 1 ,
711
727
warnoptions = ['default' ])
712
728
self .check_config ("init_env_dev_mode" , config , preconfig )
713
729
714
730
def test_init_env_dev_mode_alloc (self ):
715
- preconfig = dict (self .INIT_ENV_PRECONFIG ,
716
- allocator = PYMEM_ALLOCATOR_MALLOC )
717
- config = dict (self .INIT_ENV_CONFIG ,
718
- dev_mode = 1 ,
731
+ preconfig = dict (allocator = PYMEM_ALLOCATOR_MALLOC )
732
+ config = dict (dev_mode = 1 ,
733
+ faulthandler = 1 ,
719
734
warnoptions = ['default' ])
720
735
self .check_config ("init_env_dev_mode_alloc" , config , preconfig )
721
736
@@ -800,6 +815,7 @@ def test_init_dont_configure_locale(self):
800
815
# _PyPreConfig.configure_locale=0
801
816
preconfig = {
802
817
'configure_locale' : 0 ,
818
+ 'coerce_c_locale' : 0 ,
803
819
}
804
820
self .check_config ("init_dont_configure_locale" , {}, preconfig ,
805
821
api = CONFIG_INIT_PYTHON )
0 commit comments