1111import sys
1212
1313
14+ MS_WINDOWS = (os .name == 'nt' )
15+
16+
1417class EmbeddingTestsMixin :
1518 def setUp (self ):
1619 here = os .path .abspath (__file__ )
1720 basepath = os .path .dirname (os .path .dirname (os .path .dirname (here )))
1821 exename = "_testembed"
19- if sys . platform . startswith ( "win" ) :
22+ if MS_WINDOWS :
2023 ext = ("_d" if "_d" in sys .executable else "" ) + ".exe"
2124 exename += ext
2225 exepath = os .path .dirname (sys .executable )
@@ -38,7 +41,7 @@ def run_embedded_interpreter(self, *args, env=None):
3841 """Runs a test in the embedded interpreter"""
3942 cmd = [self .test_exe ]
4043 cmd .extend (args )
41- if env is not None and sys . platform == 'win32' :
44+ if env is not None and MS_WINDOWS :
4245 # Windows requires at least the SYSTEMROOT environment variable to
4346 # start Python.
4447 env = env .copy ()
@@ -199,7 +202,7 @@ def test_pre_initialization_api(self):
199202 """
200203 env = dict (os .environ , PYTHONPATH = os .pathsep .join (sys .path ))
201204 out , err = self .run_embedded_interpreter ("pre_initialization_api" , env = env )
202- if sys . platform == "win32" :
205+ if MS_WINDOWS :
203206 expected_path = self .test_exe
204207 else :
205208 expected_path = os .path .join (os .getcwd (), "spam" )
@@ -253,25 +256,14 @@ def test_initialize_pymain(self):
253256
254257class InitConfigTests (EmbeddingTestsMixin , unittest .TestCase ):
255258 maxDiff = 4096
256- UTF8_MODE_ERRORS = ('surrogatepass' if sys . platform == 'win32'
257- else 'surrogateescape' )
258- # FIXME: untested core configuration variables
259+ UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape' )
260+
261+ # core config
259262 UNTESTED_CORE_CONFIG = (
260- 'base_exec_prefix' ,
261- 'base_prefix' ,
263+ # FIXME: untested core configuration variables
262264 'dll_path' ,
263- 'exec_prefix' ,
264265 'executable' ,
265- 'home' ,
266- 'legacy_windows_fs_encoding' ,
267- 'legacy_windows_stdio' ,
268- 'module_search_path_env' ,
269266 'module_search_paths' ,
270- 'prefix' ,
271- )
272- # FIXME: untested main configuration variables
273- UNTESTED_MAIN_CONFIG = (
274- 'module_search_path' ,
275267 )
276268 DEFAULT_CORE_CONFIG = {
277269 'install_signal_handlers' : 1 ,
@@ -304,6 +296,13 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
304296 'xoptions' : [],
305297 'warnoptions' : [],
306298
299+ 'module_search_path_env' : None ,
300+ 'home' : None ,
301+ 'prefix' : sys .prefix ,
302+ 'base_prefix' : sys .base_prefix ,
303+ 'exec_prefix' : sys .exec_prefix ,
304+ 'base_exec_prefix' : sys .base_exec_prefix ,
305+
307306 'isolated' : 0 ,
308307 'site_import' : 1 ,
309308 'bytes_warning' : 0 ,
@@ -325,6 +324,63 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
325324 '_check_hash_pycs_mode' : 'default' ,
326325 '_frozen' : 0 ,
327326 }
327+ if MS_WINDOWS :
328+ DEFAULT_CORE_CONFIG .update ({
329+ 'legacy_windows_fs_encoding' : 0 ,
330+ 'legacy_windows_stdio' : 0 ,
331+ })
332+
333+ # main config
334+ UNTESTED_MAIN_CONFIG = (
335+ # FIXME: untested main configuration variables
336+ 'module_search_path' ,
337+ )
338+ COPY_MAIN_CONFIG = (
339+ # Copy core config to main config for expected values
340+ 'argv' ,
341+ 'base_exec_prefix' ,
342+ 'base_prefix' ,
343+ 'exec_prefix' ,
344+ 'executable' ,
345+ 'install_signal_handlers' ,
346+ 'prefix' ,
347+ 'pycache_prefix' ,
348+ 'warnoptions' ,
349+ # xoptions is created from core_config in check_main_config()
350+ )
351+
352+ # global config
353+ DEFAULT_GLOBAL_CONFIG = {
354+ 'Py_HasFileSystemDefaultEncoding' : 0 ,
355+ 'Py_HashRandomizationFlag' : 1 ,
356+ '_Py_HasFileSystemDefaultEncodeErrors' : 0 ,
357+ }
358+ COPY_GLOBAL_CONFIG = [
359+ # Copy core config to global config for expected values
360+ # True means that the core config value is inverted (0 => 1 and 1 => 0)
361+ ('Py_BytesWarningFlag' , 'bytes_warning' ),
362+ ('Py_DebugFlag' , 'parser_debug' ),
363+ ('Py_DontWriteBytecodeFlag' , 'write_bytecode' , True ),
364+ ('Py_FileSystemDefaultEncodeErrors' , 'filesystem_errors' ),
365+ ('Py_FileSystemDefaultEncoding' , 'filesystem_encoding' ),
366+ ('Py_FrozenFlag' , '_frozen' ),
367+ ('Py_IgnoreEnvironmentFlag' , 'use_environment' , True ),
368+ ('Py_InspectFlag' , 'inspect' ),
369+ ('Py_InteractiveFlag' , 'interactive' ),
370+ ('Py_IsolatedFlag' , 'isolated' ),
371+ ('Py_NoSiteFlag' , 'site_import' , True ),
372+ ('Py_NoUserSiteDirectory' , 'user_site_directory' , True ),
373+ ('Py_OptimizeFlag' , 'optimization_level' ),
374+ ('Py_QuietFlag' , 'quiet' ),
375+ ('Py_UTF8Mode' , 'utf8_mode' ),
376+ ('Py_UnbufferedStdioFlag' , 'buffered_stdio' , True ),
377+ ('Py_VerboseFlag' , 'verbose' ),
378+ ]
379+ if MS_WINDOWS :
380+ COPY_GLOBAL_CONFIG .extend ((
381+ ('Py_LegacyWindowsFSEncodingFlag' , 'legacy_windows_fs_encoding' ),
382+ ('Py_LegacyWindowsStdioFlag' , 'legacy_windows_stdio' ),
383+ ))
328384
329385 def get_stdio_encoding (self , env ):
330386 code = 'import sys; print(sys.stdout.encoding, sys.stdout.errors)'
@@ -355,18 +411,31 @@ def get_filesystem_encoding(self, isolated, env):
355411 out = proc .stdout .rstrip ()
356412 return out .split ()
357413
358- def check_config (self , testname , expected ):
359- expected = dict (self .DEFAULT_CORE_CONFIG , ** expected )
414+ def main_xoptions (self , xoptions_list ):
415+ xoptions = {}
416+ for opt in xoptions_list :
417+ if '=' in opt :
418+ key , value = opt .split ('=' , 1 )
419+ xoptions [key ] = value
420+ else :
421+ xoptions [opt ] = True
422+ return xoptions
360423
361- env = dict (os .environ )
362- for key in list (env ):
363- if key .startswith ('PYTHON' ):
364- del env [key ]
365- # Disable C locale coercion and UTF-8 mode to not depend
366- # on the current locale
367- env ['PYTHONCOERCECLOCALE' ] = '0'
368- env ['PYTHONUTF8' ] = '0'
424+ def check_main_config (self , config ):
425+ core_config = config ['core_config' ]
426+ main_config = config ['main_config' ]
427+
428+ # main config
429+ for key in self .UNTESTED_MAIN_CONFIG :
430+ del main_config [key ]
369431
432+ expected_main = {}
433+ for key in self .COPY_MAIN_CONFIG :
434+ expected_main [key ] = core_config [key ]
435+ expected_main ['xoptions' ] = self .main_xoptions (core_config ['xoptions' ])
436+ self .assertEqual (main_config , expected_main )
437+
438+ def check_core_config (self , config , expected , env ):
370439 if expected ['stdio_encoding' ] is None or expected ['stdio_errors' ] is None :
371440 res = self .get_stdio_encoding (env )
372441 if expected ['stdio_encoding' ] is None :
@@ -380,74 +449,45 @@ def check_config(self, testname, expected):
380449 if expected ['filesystem_errors' ] is None :
381450 expected ['filesystem_errors' ] = res [1 ]
382451
383- out , err = self .run_embedded_interpreter (testname , env = env )
384- # Ignore err
452+ core_config = dict (config ['core_config' ])
453+ for key in self .UNTESTED_CORE_CONFIG :
454+ core_config .pop (key , None )
455+ self .assertEqual (core_config , expected )
385456
386- config = json . loads ( out )
457+ def check_global_config ( self , config ):
387458 core_config = config ['core_config' ]
388- executable = core_config ['executable' ]
389- main_config = config ['main_config' ]
390459
391- for key in self .UNTESTED_MAIN_CONFIG :
392- del main_config [key ]
393-
394- expected_main = {
395- 'install_signal_handlers' : core_config ['install_signal_handlers' ],
396- 'argv' : [],
397- 'prefix' : sys .prefix ,
398- 'executable' : core_config ['executable' ],
399- 'base_prefix' : sys .base_prefix ,
400- 'base_exec_prefix' : sys .base_exec_prefix ,
401- 'warnoptions' : core_config ['warnoptions' ],
402- 'xoptions' : {},
403- 'pycache_prefix' : core_config ['pycache_prefix' ],
404- 'exec_prefix' : core_config ['exec_prefix' ],
405- }
406- self .assertEqual (main_config , expected_main )
407-
408-
409- copy_global_config = [
410- ('Py_BytesWarningFlag' , 'bytes_warning' ),
411- ('Py_DebugFlag' , 'parser_debug' ),
412- ('Py_DontWriteBytecodeFlag' , 'write_bytecode' , True ),
413- ('Py_FileSystemDefaultEncodeErrors' , 'filesystem_errors' ),
414- ('Py_FileSystemDefaultEncoding' , 'filesystem_encoding' ),
415- ('Py_FrozenFlag' , '_frozen' ),
416- ('Py_IgnoreEnvironmentFlag' , 'use_environment' , True ),
417- ('Py_InspectFlag' , 'inspect' ),
418- ('Py_InteractiveFlag' , 'interactive' ),
419- ('Py_IsolatedFlag' , 'isolated' ),
420- ('Py_NoSiteFlag' , 'site_import' , True ),
421- ('Py_NoUserSiteDirectory' , 'user_site_directory' , True ),
422- ('Py_OptimizeFlag' , 'optimization_level' ),
423- ('Py_QuietFlag' , 'quiet' ),
424- ('Py_UTF8Mode' , 'utf8_mode' ),
425- ('Py_UnbufferedStdioFlag' , 'buffered_stdio' , True ),
426- ('Py_VerboseFlag' , 'verbose' ),
427- ]
428- if os .name == 'nt' :
429- copy_global_config .extend ((
430- ('Py_LegacyWindowsFSEncodingFlag' , 'legacy_windows_fs_encoding' ),
431- ('Py_LegacyWindowsStdioFlag' , 'legacy_windows_stdio' ),
432- ))
433-
434- expected_global = {}
435- for item in copy_global_config :
460+ expected_global = dict (self .DEFAULT_GLOBAL_CONFIG )
461+ for item in self .COPY_GLOBAL_CONFIG :
436462 if len (item ) == 3 :
437463 global_key , core_key , opposite = item
438464 expected_global [global_key ] = 0 if core_config [core_key ] else 1
439465 else :
440466 global_key , core_key = item
441467 expected_global [global_key ] = core_config [core_key ]
442468
443- expected_global ['Py_HasFileSystemDefaultEncoding' ] = 0
444- expected_global ['_Py_HasFileSystemDefaultEncodeErrors' ] = 0
445- expected_global ['Py_HashRandomizationFlag' ] = 1
446469 self .assertEqual (config ['global_config' ], expected_global )
447470
448- for key in self .UNTESTED_CORE_CONFIG :
449- core_config .pop (key , None )
450- self .assertEqual (core_config , expected )
471+ def check_config (self , testname , expected ):
472+ expected = dict (self .DEFAULT_CORE_CONFIG , ** expected )
473+
474+ env = dict (os .environ )
475+ # Remove PYTHON* environment variables to get deterministic environment
476+ for key in list (env ):
477+ if key .startswith ('PYTHON' ):
478+ del env [key ]
479+ # Disable C locale coercion and UTF-8 mode to not depend
480+ # on the current locale
481+ env ['PYTHONCOERCECLOCALE' ] = '0'
482+ env ['PYTHONUTF8' ] = '0'
483+
484+ out , err = self .run_embedded_interpreter (testname , env = env )
485+ # Ignore err
486+ config = json .loads (out )
487+
488+ self .check_core_config (config , expected , env )
489+ self .check_main_config (config )
490+ self .check_global_config (config )
451491
452492 def test_init_default_config (self ):
453493 self .check_config ("init_default_config" , {})
@@ -495,7 +535,10 @@ def test_init_from_config(self):
495535
496536 'pycache_prefix' : 'conf_pycache_prefix' ,
497537 'program_name' : './conf_program_name' ,
538+ 'argv' : ['-c' , 'pass' ],
498539 'program' : 'conf_program' ,
540+ 'xoptions' : ['core_xoption1=3' , 'core_xoption2=' , 'core_xoption3' ],
541+ 'warnoptions' : ['default' , 'error::ResourceWarning' ],
499542
500543 'site_import' : 0 ,
501544 'bytes_warning' : 1 ,
0 commit comments