run the tests in programstestembed c tests for the cpython embedding apis pycoreconfiginitcompatconfig pycoreconfiginitpythonconfig pycoreconfiginitisolatedconfig if we are running from a build dir but the stdlib has been installed some tests need to expect different results remove python environment variables to get deterministic environment this is needed otherwise we get a fatal error pyinitialize unable to get the locale encoding lookuperror no codec search functions registered can t find encoding runs a test in the embedded interpreter cmd self testexe cmd extendargs if env is not none and mswindows windows requires at least the systemroot environment variable to start python env env copy env systemroot os environ systemroot p subprocess popencmd stdoutsubprocess pipe stderrsubprocess pipe universalnewlinestrue envenv cwdcwd try out err p communicateinputinput timeouttimeout except p terminate p wait raise if p returncode returncode and support verbose printf cmd failed printfstdout nout printfstderr nerr print self assertequalp returncode returncode bad returncode d stderr is r p returncode err return out err def runrepeatedinitandsubinterpretersself out err self runembeddedinterpretertestrepeatedinitandsubinterpreters self assertequalerr the output from testembed looks like this pass 1 interp 0 0x1cf9330 thread state 0x1cf9700 idmodules 139650431942728 interp 1 0x1d4f690 thread state 0x1d35350 idmodules 139650431165784 interp 2 0x1d5a690 thread state 0x1d99ed0 idmodules 139650413140368 interp 3 0x1d4f690 thread state 0x1dc3340 idmodules 139650412862200 interp 0 0x1cf9330 thread state 0x1cf9700 idmodules 139650431942728 pass 2 interppat rinterp d 0xdaf rthread state 0xdaf ridmodules d interp namedtupleinterp id interp tstate modules numloops 1 currentrun for line in out splitlines if line pass formatnumloops self assertequallencurrentrun 0 if support verbose 1 printline numloops 1 continue self assertlesslencurrentrun 5 match re matchinterppat line if match is none self assertregexline interppat parse the line from the loop the first line is the main interpreter and the 3 afterward are subinterpreters interp interpmatch groups if support verbose 1 printinterp self asserttrueinterp interp self asserttrueinterp tstate self asserttrueinterp modules currentrun appendinterp the last line in the loop should be the same as the first if lencurrentrun 5 main currentrun0 self assertequalinterp main yield currentrun currentrun class embeddingtestsembeddingtestsmixin unittest testcase maxdiff 100 50 def testsubinterpsmainself for run in self runrepeatedinitandsubinterpreters main run0 self assertequalmain id 0 def testsubinterpsdifferentidsself for run in self runrepeatedinitandsubinterpreters main subs run mainid intmain id for i sub in enumeratesubs self assertequalsub id strmainid i 1 def testsubinterpsdistinctstateself for run in self runrepeatedinitandsubinterpreters main subs run if 0x0 in main xxx fix on windows and other platforms something is going on with the pointers in programstestembed c interp interp is 0x0 and interp modules is the same between interpreters raise unittest skiptest platform prints pointers as 0x0 for sub in subs a new subinterpreter may have the same pyinterpreterstate pointer as a previous one if the earlier one has already been destroyed so we compare with the main interpreter the same applies to tstate self assertnotequalsub interp main interp self assertnotequalsub tstate main tstate self assertnotequalsub modules main modules def testrepeatedinitandinittabself out err self runembeddedinterpretertestrepeatedinitandinittab self assertequalerr lines f pass i for i in range1 initloops1 lines n joinlines n self assertequalout lines def testforcedioencodingself checks forced configuration of embedded interpreter io streams env dictos environ pythonioencodingutf8 surrogateescape out err self runembeddedinterpretertestforcedioencoding envenv if support verbose 1 print printout printerr expectedstreamencoding utf8 expectederrors surrogateescape expectedoutput n join use defaults expected encoding default expected errors default stdin inencoding errors stdout outencoding errors stderr outencoding backslashreplace set errors only expected encoding default expected errors ignore stdin inencoding ignore stdout outencoding ignore stderr outencoding backslashreplace set encoding only expected encoding iso88591 expected errors default stdin iso88591 errors stdout iso88591 errors stderr iso88591 backslashreplace set encoding and errors expected encoding iso88591 expected errors replace stdin iso88591 replace stdout iso88591 replace stderr iso88591 backslashreplace expectedoutput expectedoutput format inencodingexpectedstreamencoding outencodingexpectedstreamencoding errorsexpectederrors this is useful if we ever trip over odd platform behaviour self maxdiff none self assertequalout strip expectedoutput def testpreinitializationapiself env dictos environ pythonpathos pathsep joinsys path out err self runembeddedinterpretertestpreinitializationapi envenv if mswindows expectedpath self testexe else expectedpath os path joinos getcwd spam expectedoutput fsys executable expectedpathn self assertinexpectedoutput out self assertequalerr def testpreinitializationsysoptionsself env removepythonenvvars env pythonpath os pathsep joinsys path out err self runembeddedinterpreter testpreinitializationsysoptions envenv expectedoutput sys warnoptions once module default n sys xoptions notanoption 1 alsonotanoption 2 n warnings filters 3 default module once n self assertinexpectedoutput out self assertequalerr def testbpo20891self out err self runembeddedinterpretertestbpo20891 self assertequalout self assertequalerr def testinitializetwiceself out err self runembeddedinterpretertestinitializetwice self assertequalout self assertequalerr def testinitializepymainself out err self runembeddedinterpretertestinitializepymain self assertequalout rstrip pymain after pyinitialize sys argv c arg2 self assertequalerr def testrunmainself out err self runembeddedinterpretertestrunmain self assertequalout rstrip pyrunmain sys argv c arg2 self assertequalerr def testrunmainloopself bpo40413 calling pyinitializefromconfigpyrunmain multiple times must not crash nloop 5 out err self runembeddedinterpretertestrunmainloop self assertequalout pyrunmain sys argv c arg2 n nloop self assertequalerr def testfinalizestructseqself bpo46417 pyfinalize clears structseq static types check that sys attributes using struct types still work when pyfinalizepyinitialize is called multiple times print calls typetpreprinstance and so checks that the types are still working properly script support findfile testembedstructseq py with openscript encodingutf8 as fp code fp read out err self runembeddedinterpretertestrepeatedinitexec code self assertequalout tests passedn initloops def testsimpleinitializationapiself testembed now uses pyinitializefromconfig by default this case specifically checks pyinitializeex still works out err self runembeddedinterpretertestrepeatedsimpleinit self assertequalout finalizedn initloops support requiresspecialization def testspecializedstaticcodegetsunspecializedatpyfinalizeself https github compythoncpythonissues92031 code textwrap dedent import dis import importlib bootstrap import opcode import test testdis def isspecializedf for instruction in dis getinstructionsf adaptivetrue opname instruction opname if opname in opcode specializedopmap exclude superinstructions and not in opname return true return false func importlib bootstrap handlefromlist copy the code to unspecialize it func code func code replace assert not isspecializedfunc specialized instructions found for i in rangetest testdis adaptivewarmupdelay funcimportlib bootstrap x lambda args none assert isspecializedfunc no specialized instructions found printtests passed bpo47182 unicodeobject c ucnhashcapi was not reset on shutdown marker to read the default configuration getdefaultconfig marker to ignore a configuration parameter global config copy core config to global config for expected values true means that the core config value is inverted 0 1 and 1 0 clear cache use s to not import the site module get the proper configuration when testembed is run from a venv bpo35313 args sys executable s c code proc subprocess runargs envenv stdoutsubprocess pipe stderrsubprocess pipe if proc returncode raise exceptionffailed to get the default config fstdoutproc stdout r stderrproc stderr r stdout proc stdout decode utf8 ignore stderr try return json loadsstdout except json jsondecodeerror self failffail to decode stdout stdout r def getexpectedconfigself cls initconfigtests if cls expectedconfig is none cls expectedconfig self getexpectedconfigimpl get a copy configs for configkey configvalue in cls expectedconfig items config for key value in configvalue items if isinstancevalue list value value copy configkey value configsconfigkey config return configs def getexpectedconfigself expectedpreconfig expected env api modifypathcbnone configs self getexpectedconfig preconfig configs preconfig for key value in expectedpreconfig items if value is self getdefaultconfig expectedpreconfigkey preconfigkey if not expectedpreconfig configurelocale or api apicompat there is no easy way to get the locale encoding before setlocalelcctype is called don t test encodings for key in filesystemencoding filesystemerrors stdioencoding stdioerrors expectedkey self ignoreconfig if not expectedpreconfig configurelocale utf8 mode depends on the locale there is no easy way to guess if utf8 mode will be enabled or not if the locale is not configured expectedpreconfig utf8mode self ignoreconfig if expectedpreconfig utf8mode 1 if expected filesystemencoding is self getdefaultconfig expected filesystemencoding utf8 if expected filesystemerrors is self getdefaultconfig expected filesystemerrors self utf8modeerrors if expected stdioencoding is self getdefaultconfig expected stdioencoding utf8 if expected stdioerrors is self getdefaultconfig expected stdioerrors surrogateescape if mswindows defaultexecutable self testexe elif expected programname is not self getdefaultconfig defaultexecutable os path abspathexpected programname else defaultexecutable os path joinos getcwd testembed if expected executable is self getdefaultconfig expected executable defaultexecutable if expected baseexecutable is self getdefaultconfig expected baseexecutable defaultexecutable if expected programname is self getdefaultconfig expected programname testembed config configs config for key value in expected items if value is self getdefaultconfig expectedkey configkey if expected modulesearchpaths is not self ignoreconfig pythonpathenv expected pythonpathenv if pythonpathenv is not none paths pythonpathenv splitos path pathsep expected modulesearchpaths paths expected modulesearchpaths if modifypathcb is not none expected modulesearchpaths expected modulesearchpaths copy modifypathcbexpected modulesearchpaths for key in self copypreconfig if key not in expectedpreconfig expectedpreconfigkey expectedkey def checkpreconfigself configs expected preconfig dictconfigs preconfig for key value in listexpected items if value is self ignoreconfig preconfig popkey none del expectedkey self assertequalpreconfig expected def checkconfigself configs expected config dictconfigs config if mswindows value config getkey programname if value and isinstancevalue str value value lenvalue lower removesuffix exe if debugbuildsys executable value value lenvalue lower removesuffix d configkey value for key value in listexpected items if value is self ignoreconfig config popkey none del expectedkey self assertequalconfig expected def checkglobalconfigself configs preconfig configs preconfig config configs config expected dictself defaultglobalconfig for item in self copyglobalconfig if lenitem 3 globalkey corekey opposite item expectedglobalkey 0 if configcorekey else 1 else globalkey corekey item expectedglobalkey configcorekey for item in self copyglobalpreconfig if lenitem 3 globalkey corekey opposite item expectedglobalkey 0 if preconfigcorekey else 1 else globalkey corekey item expectedglobalkey preconfigcorekey self assertequalconfigs globalconfig expected def checkallconfigsself testname expectedconfignone expectedpreconfignone modifypathcbnone stderrnone api preconfigapinone envnone ignorestderrfalse cwdnone newenv removepythonenvvars if env is not none newenv updateenv env newenv if preconfigapi is none preconfigapi api if preconfigapi apiisolated defaultpreconfig self preconfigisolated elif preconfigapi apipython defaultpreconfig self preconfigpython else defaultpreconfig self preconfigcompat if expectedpreconfig is none expectedpreconfig expectedpreconfig dictdefaultpreconfig expectedpreconfig if expectedconfig is none expectedconfig if api apipython defaultconfig self configpython elif api apiisolated defaultconfig self configisolated else defaultconfig self configcompat expectedconfig dictdefaultconfig expectedconfig self getexpectedconfigexpectedpreconfig expectedconfig env api modifypathcb out err self runembeddedinterpretertestname envenv cwdcwd if stderr is none and not expectedconfig verbose stderr if stderr is not none and not ignorestderr self assertequalerr rstrip stderr try configs json loadsout except json jsondecodeerror self failffail to decode stdout out r self checkpreconfigconfigs expectedpreconfig self checkconfigconfigs expectedconfig self checkglobalconfigconfigs return configs def testinitdefaultconfigself self checkallconfigstestinitinitializeconfig apiapicompat def testpreinitcompatconfigself self checkallconfigstestpreinitcompatconfig apiapicompat def testinitcompatconfigself self checkallconfigstestinitcompatconfig apiapicompat def testinitglobalconfigself preconfig utf8mode 1 config programname globalvar siteimport 0 byteswarning 1 warnoptions default byteswarning inspect 1 interactive 1 optimizationlevel 2 writebytecode 0 verbose 1 quiet 1 bufferedstdio 0 usersitedirectory 0 pathconfigwarnings 0 self checkallconfigstestinitglobalconfig config preconfig apiapicompat def testinitfromconfigself preconfig allocator pymemallocatormalloc utf8mode 1 config installsignalhandlers 0 usehashseed 1 hashseed 123 tracemalloc 2 perfprofiling 0 importtime 1 codedebugranges 0 showrefcount 1 mallocstats 1 stdioencoding iso88591 stdioerrors replace pycacheprefix confpycacheprefix programname confprogramname argv c arg2 origargv python3 w cmdlinewarnoption x cmdlinexoption c pass arg2 parseargv 2 xoptions configxoption13 configxoption2 configxoption3 cmdlinexoption warnoptions cmdlinewarnoption default byteswarning configwarnoption runcommand passn siteimport 0 byteswarning 1 inspect 1 interactive 1 optimizationlevel 2 writebytecode 0 verbose 1 quiet 1 configurecstdio 1 bufferedstdio 0 usersitedirectory 0 faulthandler 1 platlibdir myplatlibdir modulesearchpaths self ignoreconfig safepath 1 intmaxstrdigits 31337 cpucount 4321 checkhashpycsmode always pathconfigwarnings 0 if pystats config pystats 1 self checkallconfigstestinitfromconfig config preconfig apiapicompat def testinitcompatenvself preconfig allocator pymemallocatormalloc config usehashseed 1 hashseed 42 tracemalloc 2 perfprofiling 0 importtime 1 codedebugranges 0 mallocstats 1 inspect 1 optimizationlevel 2 pythonpathenv mypath pycacheprefix envpycacheprefix writebytecode 0 verbose 1 bufferedstdio 0 stdioencoding iso88591 stdioerrors replace usersitedirectory 0 faulthandler 1 warnoptions envvar platlibdir envplatlibdir modulesearchpaths self ignoreconfig safepath 1 intmaxstrdigits 4567 if pystats config pystats 1 self checkallconfigstestinitcompatenv config preconfig apiapicompat def testinitpythonenvself preconfig allocator pymemallocatormalloc utf8mode 1 config usehashseed 1 hashseed 42 tracemalloc 2 perfprofiling 0 importtime 1 codedebugranges 0 mallocstats 1 inspect 1 optimizationlevel 2 pythonpathenv mypath pycacheprefix envpycacheprefix writebytecode 0 verbose 1 bufferedstdio 0 stdioencoding iso88591 stdioerrors replace usersitedirectory 0 faulthandler 1 warnoptions envvar platlibdir envplatlibdir modulesearchpaths self ignoreconfig safepath 1 intmaxstrdigits 4567 if pystats config pystats 1 self checkallconfigstestinitpythonenv config preconfig apiapipython def testinitenvdevmodeself preconfig dictallocatorpymemallocatordebug config dictdevmode1 faulthandler1 warnoptions default self checkallconfigstestinitenvdevmode config preconfig apiapicompat def testinitenvdevmodeallocself preconfig dictallocatorpymemallocatormalloc config dictdevmode1 faulthandler1 warnoptions default self checkallconfigstestinitenvdevmodealloc config preconfig apiapicompat def testinitdevmodeself preconfig allocator pymemallocatordebug config faulthandler 1 devmode 1 warnoptions default self checkallconfigstestinitdevmode config preconfig apiapipython def testpreinitparseargvself preinitialize implicitly using argv make sure that x dev is used to configure the allocation in preinitialization preconfig allocator pymemallocatordebug config argv script py origargv python3 x dev p script py runfilename os path abspath script py devmode 1 faulthandler 1 warnoptions default xoptions dev safepath 1 self checkallconfigstestpreinitparseargv config preconfig apiapipython def testpreinitdontparseargvself x dev must be ignored by isolated preconfiguration preconfig isolated 0 argv python3 e i p x dev x utf8 script py config argv argv origargv argv isolated 0 self checkallconfigstestpreinitdontparseargv config preconfig apiapiisolated def testinitisolatedflagself config isolated 1 safepath 1 useenvironment 0 usersitedirectory 0 self checkallconfigstestinitisolatedflag config apiapipython def testpreinitisolated1self pypreconfig isolated1 pycoreconfig isolated not set config isolated 1 safepath 1 useenvironment 0 usersitedirectory 0 self checkallconfigstestpreinitisolated1 config apiapicompat def testpreinitisolated2self pypreconfig isolated0 pycoreconfig isolated1 config isolated 1 safepath 1 useenvironment 0 usersitedirectory 0 self checkallconfigstestpreinitisolated2 config apiapicompat def testpreinitisolatedconfigself self checkallconfigstestpreinitisolatedconfig apiapiisolated def testinitisolatedconfigself self checkallconfigstestinitisolatedconfig apiapiisolated def testpreinitpythonconfigself self checkallconfigstestpreinitpythonconfig apiapipython def testinitpythonconfigself self checkallconfigstestinitpythonconfig apiapipython def testinitdontconfigurelocaleself pypreconfig configurelocale0 preconfig configurelocale 0 coerceclocale 0 self checkallconfigstestinitdontconfigurelocale preconfig apiapipython unittest skip as of 3 11 this test no longer works because path calculations do not occur on read def testinitreadsetself config programname initreadset executable myexecutable baseexecutable myexecutable def modifypathpath path insert1 testpathinsert1 path appendtestpathappend self checkallconfigstestinitreadset config apiapipython modifypathcbmodifypath def testinitsysaddself config faulthandler 1 xoptions configxoption cmdlinexoption sysaddxoption faulthandler warnoptions ignore cmdlinewarnoption ignore sysaddwarnoption ignore configwarnoption origargv python3 w ignore cmdlinewarnoption x cmdlinexoption self checkallconfigstestinitsysadd config apiapipython def testinitrunmainself code import testinternalcapi json printjson dumpstestinternalcapi getconfigs config argv c arg2 origargv python3 c code arg2 programname python3 runcommand code n parseargv 2 syspath0 self checkallconfigstestinitrunmain config apiapipython def testinitmainself code import testinternalcapi json printjson dumpstestinternalcapi getconfigs config argv c arg2 origargv python3 c code arg2 programname python3 runcommand code n parseargv 2 initmain 0 syspath0 self checkallconfigstestinitmain config apiapipython stderrrun python code before pyinitializemain def testinitparseargvself config parseargv 2 argv c arg1 v arg3 origargv argv0 e c pass arg1 v arg3 programname argv0 runcommand passn useenvironment 0 self checkallconfigstestinitparseargv config apiapipython def testinitdontparseargvself preconfig parseargv 0 config parseargv 0 argv argv0 e c pass arg1 v arg3 origargv argv0 e c pass arg1 v arg3 programname argv0 self checkallconfigstestinitdontparseargv config preconfig apiapipython def defaultprogramnameself config if mswindows programname python executable self testexe else programname python3 if macos executable self testexe else executable shutil whichprogramname or config update programname programname baseexecutable executable executable executable def testinitsetpathself test pysetpath config self getexpectedconfig paths config config modulesearchpaths config modulesearchpaths paths prefix baseprefix execprefix baseexecprefix the current getpath c doesn t determine the stdlib dir in this case stdlibdir self defaultprogramnameconfig env testpath os path pathsep joinpaths self checkallconfigstestinitsetpath config apiapicompat envenv ignorestderrtrue def testinitsetpathconfigself test pysetpath with pyconfig config self getexpectedconfig paths config config modulesearchpaths config set by pysetpath modulesearchpaths paths prefix baseprefix execprefix baseexecprefix the current getpath c doesn t determine the stdlib dir in this case stdlibdir usefrozenmodules not support pydebug overridden by pyconfig programname confprogramname baseexecutable confexecutable executable confexecutable env testpath os path pathsep joinpaths self checkallconfigstestinitsetpathconfig config apiapipython envenv ignorestderrtrue def modulesearchpathsself prefixnone execprefixnone config self getexpectedconfig if prefix is none prefix config config prefix if execprefix is none execprefix config config prefix if mswindows return config config modulesearchpaths else ver sys versioninfo return os path joinprefix sys platlibdir f pythonver majorver minor zip os path joinprefix sys platlibdir f pythonver major ver minor os path joinexecprefix sys platlibdir f pythonver major ver minor libdynload contextlib contextmanager def tmpdirwithpythonself subdirnone temporary directory with a copy of the python program with tempfile temporarydirectory as tmpdir bpo38234 on macos and freebsd the temporary directory can be symbolic link for example tmp can be a symbolic link to vartmp call realpath to resolve all symbolic links tmpdir os path realpathtmpdir if subdir tmpdir os path normpathos path jointmpdir subdir os makedirstmpdir if mswindows copy pythonxy dll or pythonxyd dll import fnmatch exedir os path dirnameself testexe for f in os listdirexedir if fnmatch fnmatchf dll shutil copyfileos path joinexedir f os path jointmpdir f copy python program execcopy os path jointmpdir os path basenameself testexe shutil copyfileself testexe execcopy shutil copystatself testexe execcopy self testexe execcopy yield tmpdir def testinitsetpythonhomeself test pysetpythonhomehome with pythonpath env var config self getexpectedconfig paths config config modulesearchpaths pathsstr os path pathsep joinpaths for path in paths if not os path isdirpath continue if os path existsos path joinpath os py home os path dirnamepath break else self failfunable to find home in paths r prefix execprefix home if mswindows stdlib os path joinhome lib because we are specifying home module search paths are fairly static expectedpaths paths0 os path joinhome dlls stdlib else version f sys versioninfo major sys versioninfo minor stdlib os path joinhome sys platlibdir f pythonversion expectedpaths self modulesearchpathsprefixhome execprefixhome config home home modulesearchpaths expectedpaths prefix prefix baseprefix prefix execprefix execprefix baseexecprefix execprefix pythonpathenv pathsstr stdlibdir stdlib self defaultprogramnameconfig env testhome home pythonpath pathsstr self checkallconfigstestinitsetpythonhome config apiapicompat envenv def testinitispythonbuildwithhomeself test pypathconfig ispythonbuild configuration gh91985 config self getexpectedconfig paths config config modulesearchpaths pathsstr os path pathsep joinpaths for path in paths if not os path isdirpath continue if os path existsos path joinpath os py home os path dirnamepath break else self failfunable to find home in paths r prefix execprefix home if mswindows stdlib os path joinhome lib because we are specifying home module search paths are fairly static expectedpaths paths0 os path joinhome dlls stdlib else version f sys versioninfo major sys versioninfo minor stdlib os path joinhome sys platlibdir f pythonversion expectedpaths self modulesearchpathsprefixhome execprefixhome config home home modulesearchpaths expectedpaths prefix prefix baseprefix prefix execprefix execprefix baseexecprefix execprefix pythonpathenv pathsstr stdlibdir stdlib the code above is taken from testinitsetpythonhome env testhome home pythonpath pathsstr env negativeispythonbuild 1 config ispythonbuild 0 self checkallconfigstestinitispythonbuild config apiapicompat envenv env negativeispythonbuild 0 config ispythonbuild 1 exedir os path dirnamesys executable with openos path joinexedir pybuilddir txt encoding utf8 as f expectedpaths1 if mswindows else 2 os path normpath os path joinexedir f f readn splitlines0 if not mswindows prefix default is set when running in build directory prefix execprefix sys prefix stdlib calculation lib is not yet supported expectedpaths0 self modulesearchpathsprefixprefix0 config updateprefixprefix baseprefixprefix execprefixexecprefix baseexecprefixexecprefix self checkallconfigstestinitispythonbuild config apiapicompat envenv def copypathsbyenvself config allconfigs self getexpectedconfig paths allconfigs config modulesearchpaths pathsstr os path pathsep joinpaths config pythonpathenv pathsstr env pythonpath pathsstr return env unittest skipifmswindows see testinitpybuilddirwin32 def testinitpybuilddirself test path configuration with pybuilddir txt configuration file with self tmpdirwithpython as tmpdir pybuilddir txt is a subdirectory relative to the current directory tmpdir vpath sysconfig getconfigvarvpath or subdir libdir libdir os path jointmpdir subdir the stdlib dir is dirnameexecutable vpath lib stdlibdir os path normpathos path jointmpdir vpath lib os mkdirlibdir filename os path jointmpdir pybuilddir txt with openfilename w encodingutf8 as fp fp writesubdir modulesearchpaths self modulesearchpaths modulesearchpaths2 stdlibdir modulesearchpaths1 libdir executable self testexe config baseexecprefix sysconfig getconfigvarexecprefix baseprefix sysconfig getconfigvarprefix baseexecutable executable executable executable modulesearchpaths modulesearchpaths stdlibdir stdlibdir env self copypathsbyenvconfig self checkallconfigstestinitcompatconfig config apiapicompat envenv ignorestderrtrue cwdtmpdir unittest skipunlessmswindows see testinitpybuilddir def testinitpybuilddirwin32self test path configuration with pybuilddir txt configuration file vpath sysconfig getconfigvarvpath subdir r pcbuildarch if os path normpathvpath countos sep 2 subdir os path joinsubdir instrumented with self tmpdirwithpythonsubdir as tmpdir the prefix is dirnameexecutable vpath prefix os path normpathos path jointmpdir vpath the stdlib dir is dirnameexecutable vpath lib stdlibdir os path normpathos path jointmpdir vpath lib filename os path jointmpdir pybuilddir txt with openfilename w encodingutf8 as fp fp writetmpdir modulesearchpaths self modulesearchpaths modulesearchpaths3 os path jointmpdir os path basenamemodulesearchpaths3 modulesearchpaths2 tmpdir modulesearchpaths1 stdlibdir executable self testexe config baseexecprefix prefix baseprefix prefix baseexecutable executable executable executable prefix prefix execprefix prefix modulesearchpaths modulesearchpaths stdlibdir stdlibdir env self copypathsbyenvconfig self checkallconfigstestinitcompatconfig config apiapicompat envenv ignorestderrfalse cwdtmpdir def testinitpyvenvcfgself test path configuration with pyvenv cfg configuration file with self tmpdirwithpython as tmpdir tempfile temporarydirectory as pyvenvhome ver sys versioninfo if not mswindows libdynload os path joinpyvenvhome sys platlibdir f pythonver major ver minor libdynload os makedirslibdynload else libfolder os path joinpyvenvhome lib os makedirslibfolder getpath py uses libos py as the landmark shutil copyfile os path joinsupport stdlibdir os py os path joinlibfolder os py filename os path jointmpdir pyvenv cfg with openfilename w encodingutf8 as fp printhome s pyvenvhome filefp printincludesystemsitepackages false filefp paths self modulesearchpaths if not mswindows paths1 libdynload else paths os path jointmpdir os path basenamepaths0 pyvenvhome os path joinpyvenvhome lib executable self testexe baseexecutable os path joinpyvenvhome os path basenameexecutable execprefix pyvenvhome config baseprefix sysconfig getconfigvarprefix baseexecprefix execprefix execprefix execprefix baseexecutable baseexecutable executable executable modulesearchpaths paths if mswindows config baseprefix pyvenvhome config prefix pyvenvhome config stdlibdir os path joinpyvenvhome lib config usefrozenmodules intnot support pydebug else cannot reliably assume stdlibdir here because it depends too much on our build but it ought to be found config stdlibdir self ignoreconfig config usefrozenmodules intnot support pydebug env self copypathsbyenvconfig self checkallconfigstestinitcompatconfig config apiapicompat envenv ignorestderrtrue cwdtmpdir unittest skipunlessmswindows specific to windows def testgetpathabspathwin32self check pyabspath is passed a backslashed path not to fall back to getfullpathnamew on startup which renormalizes the path overly currently pynormpath doesn t trim trailing dots and spaces cases c a c a c a c a c ab c ab abc abc abc abc a fos getcwda relpath gets fully normalized out err self runembeddedinterpreter testinitinitializeconfig envremovepythonenvvars pythonpath os path pathsep joinc0 for c in cases self assertequalerr try out json loadsout except json jsondecodeerror self failffail to decode stdout out r results out config modulesearchpaths for expected result in zipcases results self assertequalresult expected def testglobalpathconfigself test c api functions getting the path configuration pygetexecprefix pygetpath pygetprefix pygetprogramfullpath pygetprogramname pygetpythonhome the global path configuration pypathconfig must be a copy of the path configuration of pyinterpreter config pyconfig ctypes importhelper importmodule ctypes testinternalcapi importhelper importmodule testinternalcapi def getfuncname func getattrctypes pythonapi name func argtypes func restype ctypes cwcharp return func pygetpath getfunc pygetpath pygetprefix getfunc pygetprefix pygetexecprefix getfunc pygetexecprefix pygetprogramname getfunc pygetprogramname pygetprogramfullpath getfunc pygetprogramfullpath pygetpythonhome getfunc pygetpythonhome config testinternalcapi getconfigs config self assertequalpygetpath splitos path pathsep config modulesearchpaths self assertequalpygetprefix config prefix self assertequalpygetexecprefix config execprefix self assertequalpygetprogramname config programname self assertequalpygetprogramfullpath config executable self assertequalpygetpythonhome config home def testinitwarnoptionsself lowest to highest priority warnoptions ignore pyconfiginsert0 pywidestringlistinsert0 default pyconfig devmode1 ignore env1 pythonwarnings env var ignore env2 pythonwarnings env var ignore cmdline1 w opt command line option ignore cmdline2 w opt command line option default byteswarning pyconfig byteswarnings1 ignore pysysaddwarnoption1 pysysaddwarnoption ignore pysysaddwarnoption2 pysysaddwarnoption ignore pyconfigbeforeread pyconfig warnoptions ignore pyconfigafterread pywidestringlistappend preconfig dictallocatorpymemallocatordebug config devmode 1 faulthandler 1 byteswarning 1 warnoptions warnoptions origargv python3 wignore cmdline1 wignore cmdline2 self checkallconfigstestinitwarnoptions config preconfig apiapipython def testinitsetconfigself config initmain 0 byteswarning 2 warnoptions error byteswarning self checkallconfigstestinitsetconfig config apiapiisolated def testgetargcargvself self runembeddedinterpretertestgetargcargv ignore output def testinitusefrozenmodulesself tests on 1 off 0 1 1 for raw expected in tests optval f frozenmodulesraw config parseargv 2 argv c origargv argv0 x optval c pass programname argv0 runcommand passn useenvironment 1 xoptions optval usefrozenmodules expected env testfrozen raw1 if raw else none with self subtestreprraw self checkallconfigstestinitusefrozenmodules config apiapipython envenv def testinitmaininterpretersettingsself obmalloc 15 extensions 18 threads 110 daemonthreads 111 fork 115 exec 116 expected all optional features should be enabled featureflags obmalloc fork exec threads daemonthreads owngil true out err self runembeddedinterpreter testinitmaininterpretersettings self assertequalerr try out json loadsout except json jsondecodeerror self failf fail to decode stdout out r self assertequalout expected class setconfigtestsunittest testcase def testsetconfigself bpo42260 test pyinterpreterstatesetconfig importhelper importmodule testcapi cmd sys executable x utf8 i m test testembedsetconfig proc subprocess runcmd stdoutsubprocess pipe stderrsubprocess pipe encoding utf8 errors backslashreplace if proc returncode and support verbose printproc stdout printproc stderr self assertequalproc returncode 0 proc returncode proc stdout proc stderr class auditingtestsembeddingtestsmixin unittest testcase def testopencodehookself self runembeddedinterpretertestopencodehook def testauditself self runembeddedinterpretertestaudit def testaudittupleself self runembeddedinterpretertestaudittuple def testauditsubinterpreterself self runembeddedinterpretertestauditsubinterpreter def testauditruncommandself self runembeddedinterpretertestauditruncommand timeoutsupport shorttimeout returncode1 def testauditrunfileself self runembeddedinterpretertestauditrunfile timeoutsupport shorttimeout returncode1 def testauditruninteractivehookself startup os path joinself oldcwd oshelper testfn py with openstartup w encodingutf8 as f printimport sys filef printsys interactivehook lambda none filef try env removepythonenvvars pythonstartup startup self runembeddedinterpretertestauditruninteractivehook timeoutsupport shorttimeout returncode10 envenv finally os unlinkstartup def testauditrunstartupself startup os path joinself oldcwd oshelper testfn py with openstartup w encodingutf8 as f printpass filef try env removepythonenvvars pythonstartup startup self runembeddedinterpretertestauditrunstartup timeoutsupport shorttimeout returncode10 envenv finally os unlinkstartup def testauditrunstdinself self runembeddedinterpretertestauditrunstdin timeoutsupport shorttimeout returncode1 def testgetincompleteframeself self runembeddedinterpretertestgetincompleteframe class misctestsembeddingtestsmixin unittest testcase def testunicodeidinitself bpo42882 test that pyunicodefromid works when python is initialized multiples times self runembeddedinterpretertestunicodeidinit see bpo44133 unittest skipifos name nt pyfrozenmain is not exported on windows def testfrozenmainself env dictos environ env pythonunbuffered 1 out err self runembeddedinterpretertestfrozenmain envenv executable os path realpath argv0 expected textwrap dedentf frozen hello world sys argv argv0 e arg1 arg2 config programname argv0 config executable executable config useenvironment 1 config configurecstdio 1 config bufferedstdio 0 bpo1635741 python must release all memory at exit test pystdprintertype which is used by pysyssetpreliminarystderr set up a preliminary stderr printer until we have enough infrastructure for the io module in place pyfilenewstdprinter only accepts filenostdout or filenostderr file descriptor run the tests in programs _testembed c tests for the cpython embedding apis _pycoreconfig_initcompatconfig _pycoreconfig_initpythonconfig _pycoreconfig_initisolatedconfig if we are running from a build dir but the stdlib has been installed some tests need to expect different results remove python environment variables to get deterministic environment this is needed otherwise we get a fatal error py_initialize unable to get the locale encoding lookuperror no codec search functions registered can t find encoding runs a test in the embedded interpreter windows requires at least the systemroot environment variable to start python the output from _testembed looks like this pass 1 interp 0 0x1cf9330 thread state 0x1cf9700 id modules 139650431942728 interp 1 0x1d4f690 thread state 0x1d35350 id modules 139650431165784 interp 2 0x1d5a690 thread state 0x1d99ed0 id modules 139650413140368 interp 3 0x1d4f690 thread state 0x1dc3340 id modules 139650412862200 interp 0 0x1cf9330 thread state 0x1cf9700 id modules 139650431942728 pass 2 parse the line from the loop the first line is the main interpreter and the 3 afterward are subinterpreters the last line in the loop should be the same as the first xxx fix on windows and other platforms something is going on with the pointers in programs _testembed c interp interp is 0x0 and interp modules is the same between interpreters a new subinterpreter may have the same pyinterpreterstate pointer as a previous one if the earlier one has already been destroyed so we compare with the main interpreter the same applies to tstate checks forced configuration of embedded interpreter io streams this is useful if we ever trip over odd platform behaviour checks some key parts of the c api that need to work before the runtime is initialized via py_initialize checks that sys warnoptions and sys _xoptions can be set before the runtime is initialized otherwise they won t be effective bpo 20891 calling pygilstate_ensure in a non python thread must not crash bpo 33932 calling py_initialize twice should do nothing and not crash bpo 34008 calling py_main after py_initialize must not fail bpo 40413 calling py_initializefromconfig py_runmain multiple times must not crash bpo 46417 py_finalize clears structseq static types check that sys attributes using struct types still work when py_finalize py_initialize is called multiple times print calls type tp_repr instance and so checks that the types are still working properly _testembed now uses py_initializefromconfig by default this case specifically checks py_initialize ex still works https github com python cpython issues 92031 import dis import importlib _bootstrap import opcode import test test_dis def is_specialized f for instruction in dis get_instructions f adaptive true opname instruction opname if opname in opcode _specialized_opmap exclude superinstructions and __ not in opname return true return false func importlib _bootstrap _handle_fromlist copy the code to un specialize it func __code__ func __code__ replace assert not is_specialized func specialized instructions found for i in range test test_dis adaptive_warmup_delay func importlib _bootstrap x lambda args none assert is_specialized func no specialized instructions found print tests passed bpo 47182 unicodeobject c ucnhash_capi was not reset on shutdown marker to read the default configuration get_default_config marker to ignore a configuration parameter global config copy core config to global config for expected values true means that the core config value is inverted 0 1 and 1 0 clear cache import json import sys import _testinternalcapi configs _testinternalcapi get_configs data json dumps configs data data encode utf 8 sys stdout buffer write data sys stdout buffer flush use s to not import the site module get the proper configuration when test_embed is run from a venv bpo 35313 ignore stderr get a copy there is no easy way to get the locale encoding before setlocale lc_ctype is called don t test encodings utf 8 mode depends on the locale there is no easy way to guess if utf 8 mode will be enabled or not if the locale is not configured pre initialize implicitly using argv make sure that x dev is used to configure the allocation in preinitialization x dev must be ignored by isolated preconfiguration _pypreconfig isolated 1 _pycoreconfig isolated not set _pypreconfig isolated 0 _pycoreconfig isolated 1 _pypreconfig configure_locale 0 test py_setpath the current getpath c doesn t determine the stdlib dir in this case test py_setpath with pyconfig set by py_setpath the current getpath c doesn t determine the stdlib dir in this case overridden by pyconfig temporary directory with a copy of the python program bpo 38234 on macos and freebsd the temporary directory can be symbolic link for example tmp can be a symbolic link to var tmp call realpath to resolve all symbolic links copy pythonxy dll or pythonxy_d dll copy python program test py_setpythonhome home with pythonpath env var because we are specifying home module search paths are fairly static test _py_path_config _is_python_build configuration gh 91985 because we are specifying home module search paths are fairly static the code above is taken from test_init_setpythonhome prefix default is set when running in build directory stdlib calculation lib is not yet supported test path configuration with pybuilddir txt configuration file pybuilddir txt is a sub directory relative to the current directory tmpdir the stdlib dir is dirname executable vpath lib test path configuration with pybuilddir txt configuration file the prefix is dirname executable vpath the stdlib dir is dirname executable vpath lib test path configuration with pyvenv cfg configuration file getpath py uses lib os py as the landmark cannot reliably assume stdlib_dir here because it depends too much on our build but it ought to be found check _py_abspath is passed a backslashed path not to fall back to getfullpathnamew on startup which re normalizes the path overly currently _py_normpath doesn t trim trailing dots and spaces relpath gets fully normalized test c api functions getting the path configuration py_getexecprefix py_getpath py_getprefix py_getprogramfullpath py_getprogramname py_getpythonhome the global path configuration _py_path_config must be a copy of the path configuration of pyinterpreter config pyconfig lowest to highest priority pywidestringlist_insert 0 pyconfig dev_mode 1 pythonwarnings env var pythonwarnings env var w opt command line option w opt command line option pyconfig bytes_warnings 1 pysys_addwarnoption pysys_addwarnoption pyconfig warnoptions pywidestringlist_append ignore output all optional features should be enabled bpo 42260 test _pyinterpreterstate_setconfig bpo 42882 test that _pyunicode_fromid works when python is initialized multiples times see bpo 44133 frozen hello world sys argv argv0 e arg1 arg2 config program_name argv0 config executable executable config use_environment 1 config configure_c_stdio 1 config buffered_stdio 0 bpo 1635741 python must release all memory at exit test pystdprinter_type which is used by _pysys_setpreliminarystderr set up a preliminary stderr printer until we have enough infrastructure for the io module in place pyfile_newstdprinter only accepts fileno stdout or fileno stderr file descriptor noop noop
from test import support
from test.support import import_helper, os_helper, MS_WINDOWS
import unittest

from collections import namedtuple
import contextlib
import json
import os
import os.path
import re
import shutil
import subprocess
import sys
import sysconfig
import tempfile
import textwrap

if not support.has_subprocess_support:
    raise unittest.SkipTest("test module requires subprocess")

MACOS = (sys.platform == 'darwin')
PYMEM_ALLOCATOR_NOT_SET = 0
PYMEM_ALLOCATOR_DEBUG = 2
PYMEM_ALLOCATOR_MALLOC = 3
Py_STATS = hasattr(sys, '_stats_on')


API_COMPAT = 1

API_PYTHON = 2

API_ISOLATED = 3

INIT_LOOPS = 4
MAX_HASH_SEED = 4294967295




STDLIB_INSTALL = os.path.join(sys.prefix, sys.platlibdir,
    f'python{sys.version_info.major}.{sys.version_info.minor}')
if not os.path.isfile(os.path.join(STDLIB_INSTALL, 'os.py')):
    STDLIB_INSTALL = None

def debug_build(program):
    program = os.path.basename(program)
    name = os.path.splitext(program)[0]
    return name.casefold().endswith("_d".casefold())


def remove_python_envvars():
    env = dict(os.environ)
    
    for key in list(env):
        if key.startswith('PYTHON'):
            del env[key]
    return env


class EmbeddingTestsMixin:
    def setUp(self):
        exename = "_testembed"
        builddir = os.path.dirname(sys.executable)
        if MS_WINDOWS:
            ext = ("_d" if debug_build(sys.executable) else "") + ".exe"
            exename += ext
            exepath = builddir
        else:
            exepath = os.path.join(builddir, 'Programs')
        self.test_exe = exe = os.path.join(exepath, exename)
        if not os.path.exists(exe):
            self.skipTest("%r doesn't exist" % exe)
        
        
        
        self.oldcwd = os.getcwd()
        os.chdir(builddir)

    def tearDown(self):
        os.chdir(self.oldcwd)

    def run_embedded_interpreter(self, *args, env=None,
                                 timeout=None, returncode=0, input=None,
                                 cwd=None):
        
        cmd = [self.test_exe]
        cmd.extend(args)
        if env is not None and MS_WINDOWS:
            
            
            env = env.copy()
            env['SYSTEMROOT'] = os.environ['SYSTEMROOT']

        p = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True,
                             env=env,
                             cwd=cwd)
        try:
            (out, err) = p.communicate(input=input, timeout=timeout)
        except:
            p.terminate()
            p.wait()
            raise
        if p.returncode != returncode and support.verbose:
            print(f"--- {cmd} failed ---")
            print(f"stdout:\n{out}")
            print(f"stderr:\n{err}")
            print("------")

        self.assertEqual(p.returncode, returncode,
                         "bad returncode %d, stderr is %r" %
                         (p.returncode, err))
        return out, err

    def run_repeated_init_and_subinterpreters(self):
        out, err = self.run_embedded_interpreter("test_repeated_init_and_subinterpreters")
        self.assertEqual(err, "")

        
        
        
        
        
        
        
        
        

        interp_pat = (r"^interp (\d+) <(0x[\dA-F]+)>, "
                      r"thread state <(0x[\dA-F]+)>: "
                      r"id\(modules\) = ([\d]+)$")
        Interp = namedtuple("Interp", "id interp tstate modules")

        numloops = 1
        current_run = []
        for line in out.splitlines():
            if line == "--- Pass {} ---".format(numloops):
                self.assertEqual(len(current_run), 0)
                if support.verbose > 1:
                    print(line)
                numloops += 1
                continue

            self.assertLess(len(current_run), 5)
            match = re.match(interp_pat, line)
            if match is None:
                self.assertRegex(line, interp_pat)

            
            
            interp = Interp(*match.groups())
            if support.verbose > 1:
                print(interp)
            self.assertTrue(interp.interp)
            self.assertTrue(interp.tstate)
            self.assertTrue(interp.modules)
            current_run.append(interp)

            
            if len(current_run) == 5:
                main = current_run[0]
                self.assertEqual(interp, main)
                yield current_run
                current_run = []


class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
    maxDiff = 100 * 50

    def test_subinterps_main(self):
        for run in self.run_repeated_init_and_subinterpreters():
            main = run[0]

            self.assertEqual(main.id, '0')

    def test_subinterps_different_ids(self):
        for run in self.run_repeated_init_and_subinterpreters():
            main, *subs, _ = run

            mainid = int(main.id)
            for i, sub in enumerate(subs):
                self.assertEqual(sub.id, str(mainid + i + 1))

    def test_subinterps_distinct_state(self):
        for run in self.run_repeated_init_and_subinterpreters():
            main, *subs, _ = run

            if '0x0' in main:
                
                
                
                
                raise unittest.SkipTest('platform prints pointers as 0x0')

            for sub in subs:
                
                
                
                
                
                self.assertNotEqual(sub.interp, main.interp)
                self.assertNotEqual(sub.tstate, main.tstate)
                self.assertNotEqual(sub.modules, main.modules)

    def test_repeated_init_and_inittab(self):
        out, err = self.run_embedded_interpreter("test_repeated_init_and_inittab")
        self.assertEqual(err, "")

        lines = [f"--- Pass {i} ---" for i in range(1, INIT_LOOPS+1)]
        lines = "\n".join(lines) + "\n"
        self.assertEqual(out, lines)

    def test_forced_io_encoding(self):
        
        env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
        out, err = self.run_embedded_interpreter("test_forced_io_encoding", env=env)
        if support.verbose > 1:
            print()
            print(out)
            print(err)
        expected_stream_encoding = "utf-8"
        expected_errors = "surrogateescape"
        expected_output = '\n'.join([
        "--- Use defaults ---",
        "Expected encoding: default",
        "Expected errors: default",
        "stdin: {in_encoding}:{errors}",
        "stdout: {out_encoding}:{errors}",
        "stderr: {out_encoding}:backslashreplace",
        "--- Set errors only ---",
        "Expected encoding: default",
        "Expected errors: ignore",
        "stdin: {in_encoding}:ignore",
        "stdout: {out_encoding}:ignore",
        "stderr: {out_encoding}:backslashreplace",
        "--- Set encoding only ---",
        "Expected encoding: iso8859-1",
        "Expected errors: default",
        "stdin: iso8859-1:{errors}",
        "stdout: iso8859-1:{errors}",
        "stderr: iso8859-1:backslashreplace",
        "--- Set encoding and errors ---",
        "Expected encoding: iso8859-1",
        "Expected errors: replace",
        "stdin: iso8859-1:replace",
        "stdout: iso8859-1:replace",
        "stderr: iso8859-1:backslashreplace"])
        expected_output = expected_output.format(
                                in_encoding=expected_stream_encoding,
                                out_encoding=expected_stream_encoding,
                                errors=expected_errors)
        
        self.maxDiff = None
        self.assertEqual(out.strip(), expected_output)

    def test_pre_initialization_api(self):
        
        env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
        out, err = self.run_embedded_interpreter("test_pre_initialization_api", env=env)
        if MS_WINDOWS:
            expected_path = self.test_exe
        else:
            expected_path = os.path.join(os.getcwd(), "spam")
        expected_output = f"sys.executable: {expected_path}\n"
        self.assertIn(expected_output, out)
        self.assertEqual(err, '')

    def test_pre_initialization_sys_options(self):
        
        env = remove_python_envvars()
        env['PYTHONPATH'] = os.pathsep.join(sys.path)
        out, err = self.run_embedded_interpreter(
                        "test_pre_initialization_sys_options", env=env)
        expected_output = (
            "sys.warnoptions: ['once', 'module', 'default']\n"
            "sys._xoptions: {'not_an_option': '1', 'also_not_an_option': '2'}\n"
            "warnings.filters[:3]: ['default', 'module', 'once']\n"
        )
        self.assertIn(expected_output, out)
        self.assertEqual(err, '')

    def test_bpo20891(self):
        
        out, err = self.run_embedded_interpreter("test_bpo20891")
        self.assertEqual(out, '')
        self.assertEqual(err, '')

    def test_initialize_twice(self):
        
        out, err = self.run_embedded_interpreter("test_initialize_twice")
        self.assertEqual(out, '')
        self.assertEqual(err, '')

    def test_initialize_pymain(self):
        
        out, err = self.run_embedded_interpreter("test_initialize_pymain")
        self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")
        self.assertEqual(err, '')

    def test_run_main(self):
        out, err = self.run_embedded_interpreter("test_run_main")
        self.assertEqual(out.rstrip(), "Py_RunMain(): sys.argv=['-c', 'arg2']")
        self.assertEqual(err, '')

    def test_run_main_loop(self):
        
        
        nloop = 5
        out, err = self.run_embedded_interpreter("test_run_main_loop")
        self.assertEqual(out, "Py_RunMain(): sys.argv=['-c', 'arg2']\n" * nloop)
        self.assertEqual(err, '')

    def test_finalize_structseq(self):
        
        
        
        
        
        script = support.findfile('_test_embed_structseq.py')
        with open(script, encoding="utf-8") as fp:
            code = fp.read()
        out, err = self.run_embedded_interpreter("test_repeated_init_exec", code)
        self.assertEqual(out, 'Tests passed\n' * INIT_LOOPS)

    def test_simple_initialization_api(self):
        
        
        out, err = self.run_embedded_interpreter("test_repeated_simple_init")
        self.assertEqual(out, 'Finalized\n' * INIT_LOOPS)

    @support.requires_specialization
    def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self):
        

        code = textwrap.dedent()
        run = self.run_embedded_interpreter
        out, err = run("test_repeated_init_exec", code)
        self.assertEqual(out, 'Tests passed\n' * INIT_LOOPS)

    def test_ucnhash_capi_reset(self):
        
        code = "print('\\N{digit nine}')"
        out, err = self.run_embedded_interpreter("test_repeated_init_exec", code)
        self.assertEqual(out, '9\n' * INIT_LOOPS)

class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
    maxDiff = 4096
    UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')

    
    GET_DEFAULT_CONFIG = object()

    
    IGNORE_CONFIG = object()

    PRE_CONFIG_COMPAT = {
        '_config_init': API_COMPAT,
        'allocator': PYMEM_ALLOCATOR_NOT_SET,
        'parse_argv': 0,
        'configure_locale': 1,
        'coerce_c_locale': 0,
        'coerce_c_locale_warn': 0,
        'utf8_mode': 0,
    }
    if MS_WINDOWS:
        PRE_CONFIG_COMPAT.update({
            'legacy_windows_fs_encoding': 0,
        })
    PRE_CONFIG_PYTHON = dict(PRE_CONFIG_COMPAT,
        _config_init=API_PYTHON,
        parse_argv=1,
        coerce_c_locale=GET_DEFAULT_CONFIG,
        utf8_mode=GET_DEFAULT_CONFIG,
    )
    PRE_CONFIG_ISOLATED = dict(PRE_CONFIG_COMPAT,
        _config_init=API_ISOLATED,
        configure_locale=0,
        isolated=1,
        use_environment=0,
        utf8_mode=0,
        dev_mode=0,
        coerce_c_locale=0,
    )

    COPY_PRE_CONFIG = [
        'dev_mode',
        'isolated',
        'use_environment',
    ]

    CONFIG_COMPAT = {
        '_config_init': API_COMPAT,
        'isolated': 0,
        'use_environment': 1,
        'dev_mode': 0,

        'install_signal_handlers': 1,
        'use_hash_seed': 0,
        'hash_seed': 0,
        'int_max_str_digits': sys.int_info.default_max_str_digits,
        'cpu_count': -1,
        'faulthandler': 0,
        'tracemalloc': 0,
        'perf_profiling': 0,
        'import_time': 0,
        'code_debug_ranges': 1,
        'show_ref_count': 0,
        'dump_refs': 0,
        'dump_refs_file': None,
        'malloc_stats': 0,

        'filesystem_encoding': GET_DEFAULT_CONFIG,
        'filesystem_errors': GET_DEFAULT_CONFIG,

        'pycache_prefix': None,
        'program_name': GET_DEFAULT_CONFIG,
        'parse_argv': 0,
        'argv': [""],
        'orig_argv': [],

        'xoptions': [],
        'warnoptions': [],

        'pythonpath_env': None,
        'home': None,
        'executable': GET_DEFAULT_CONFIG,
        'base_executable': GET_DEFAULT_CONFIG,

        'prefix': GET_DEFAULT_CONFIG,
        'base_prefix': GET_DEFAULT_CONFIG,
        'exec_prefix': GET_DEFAULT_CONFIG,
        'base_exec_prefix': GET_DEFAULT_CONFIG,
        'module_search_paths': GET_DEFAULT_CONFIG,
        'module_search_paths_set': 1,
        'platlibdir': sys.platlibdir,
        'stdlib_dir': GET_DEFAULT_CONFIG,

        'site_import': 1,
        'bytes_warning': 0,
        'warn_default_encoding': 0,
        'inspect': 0,
        'interactive': 0,
        'optimization_level': 0,
        'parser_debug': 0,
        'write_bytecode': 1,
        'verbose': 0,
        'quiet': 0,
        'user_site_directory': 1,
        'configure_c_stdio': 0,
        'buffered_stdio': 1,

        'stdio_encoding': GET_DEFAULT_CONFIG,
        'stdio_errors': GET_DEFAULT_CONFIG,

        'skip_source_first_line': 0,
        'run_command': None,
        'run_module': None,
        'run_filename': None,
        'sys_path_0': None,

        '_install_importlib': 1,
        'check_hash_pycs_mode': 'default',
        'pathconfig_warnings': 1,
        '_init_main': 1,
        'use_frozen_modules': not support.Py_DEBUG,
        'safe_path': 0,
        '_is_python_build': IGNORE_CONFIG,
    }
    if Py_STATS:
        CONFIG_COMPAT['_pystats'] = 0
    if support.Py_DEBUG:
        CONFIG_COMPAT['run_presite'] = None
    if MS_WINDOWS:
        CONFIG_COMPAT.update({
            'legacy_windows_stdio': 0,
        })

    CONFIG_PYTHON = dict(CONFIG_COMPAT,
        _config_init=API_PYTHON,
        configure_c_stdio=1,
        parse_argv=2,
    )
    CONFIG_ISOLATED = dict(CONFIG_COMPAT,
        _config_init=API_ISOLATED,
        isolated=1,
        use_environment=0,
        user_site_directory=0,
        safe_path=1,
        dev_mode=0,
        install_signal_handlers=0,
        use_hash_seed=0,
        faulthandler=0,
        tracemalloc=0,
        perf_profiling=0,
        pathconfig_warnings=0,
    )
    if MS_WINDOWS:
        CONFIG_ISOLATED['legacy_windows_stdio'] = 0

    
    DEFAULT_GLOBAL_CONFIG = {
        'Py_HasFileSystemDefaultEncoding': 0,
        'Py_HashRandomizationFlag': 1,
        '_Py_HasFileSystemDefaultEncodeErrors': 0,
    }
    COPY_GLOBAL_PRE_CONFIG = [
        ('Py_UTF8Mode', 'utf8_mode'),
    ]
    COPY_GLOBAL_CONFIG = [
        
        
        ('Py_BytesWarningFlag', 'bytes_warning'),
        ('Py_DebugFlag', 'parser_debug'),
        ('Py_DontWriteBytecodeFlag', 'write_bytecode', True),
        ('Py_FileSystemDefaultEncodeErrors', 'filesystem_errors'),
        ('Py_FileSystemDefaultEncoding', 'filesystem_encoding'),
        ('Py_FrozenFlag', 'pathconfig_warnings', True),
        ('Py_IgnoreEnvironmentFlag', 'use_environment', True),
        ('Py_InspectFlag', 'inspect'),
        ('Py_InteractiveFlag', 'interactive'),
        ('Py_IsolatedFlag', 'isolated'),
        ('Py_NoSiteFlag', 'site_import', True),
        ('Py_NoUserSiteDirectory', 'user_site_directory', True),
        ('Py_OptimizeFlag', 'optimization_level'),
        ('Py_QuietFlag', 'quiet'),
        ('Py_UnbufferedStdioFlag', 'buffered_stdio', True),
        ('Py_VerboseFlag', 'verbose'),
    ]
    if MS_WINDOWS:
        COPY_GLOBAL_PRE_CONFIG.extend((
            ('Py_LegacyWindowsFSEncodingFlag', 'legacy_windows_fs_encoding'),
        ))
        COPY_GLOBAL_CONFIG.extend((
            ('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'),
        ))

    EXPECTED_CONFIG = None

    @classmethod
    def tearDownClass(cls):
        
        cls.EXPECTED_CONFIG = None

    def main_xoptions(self, xoptions_list):
        xoptions = {}
        for opt in xoptions_list:
            if '=' in opt:
                key, value = opt.split('=', 1)
                xoptions[key] = value
            else:
                xoptions[opt] = True
        return xoptions

    def _get_expected_config_impl(self):
        env = remove_python_envvars()
        code = textwrap.dedent()

        
        
        args = [sys.executable, '-S', '-c', code]
        proc = subprocess.run(args, env=env,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if proc.returncode:
            raise Exception(f"failed to get the default config: "
                            f"stdout={proc.stdout!r} stderr={proc.stderr!r}")
        stdout = proc.stdout.decode('utf-8')
        
        try:
            return json.loads(stdout)
        except json.JSONDecodeError:
            self.fail(f"fail to decode stdout: {stdout!r}")

    def _get_expected_config(self):
        cls = InitConfigTests
        if cls.EXPECTED_CONFIG is None:
            cls.EXPECTED_CONFIG = self._get_expected_config_impl()

        
        configs = {}
        for config_key, config_value in cls.EXPECTED_CONFIG.items():
            config = {}
            for key, value in config_value.items():
                if isinstance(value, list):
                    value = value.copy()
                config[key] = value
            configs[config_key] = config
        return configs

    def get_expected_config(self, expected_preconfig, expected,
                            env, api, modify_path_cb=None):
        configs = self._get_expected_config()

        pre_config = configs['pre_config']
        for key, value in expected_preconfig.items():
            if value is self.GET_DEFAULT_CONFIG:
                expected_preconfig[key] = pre_config[key]

        if not expected_preconfig['configure_locale'] or api == API_COMPAT:
            
            
            for key in ('filesystem_encoding', 'filesystem_errors',
                        'stdio_encoding', 'stdio_errors'):
                expected[key] = self.IGNORE_CONFIG

        if not expected_preconfig['configure_locale']:
            
            
            
            expected_preconfig['utf8_mode'] = self.IGNORE_CONFIG

        if expected_preconfig['utf8_mode'] == 1:
            if expected['filesystem_encoding'] is self.GET_DEFAULT_CONFIG:
                expected['filesystem_encoding'] = 'utf-8'
            if expected['filesystem_errors'] is self.GET_DEFAULT_CONFIG:
                expected['filesystem_errors'] = self.UTF8_MODE_ERRORS
            if expected['stdio_encoding'] is self.GET_DEFAULT_CONFIG:
                expected['stdio_encoding'] = 'utf-8'
            if expected['stdio_errors'] is self.GET_DEFAULT_CONFIG:
                expected['stdio_errors'] = 'surrogateescape'

        if MS_WINDOWS:
            default_executable = self.test_exe
        elif expected['program_name'] is not self.GET_DEFAULT_CONFIG:
            default_executable = os.path.abspath(expected['program_name'])
        else:
            default_executable = os.path.join(os.getcwd(), '_testembed')
        if expected['executable'] is self.GET_DEFAULT_CONFIG:
            expected['executable'] = default_executable
        if expected['base_executable'] is self.GET_DEFAULT_CONFIG:
            expected['base_executable'] = default_executable
        if expected['program_name'] is self.GET_DEFAULT_CONFIG:
            expected['program_name'] = './_testembed'

        config = configs['config']
        for key, value in expected.items():
            if value is self.GET_DEFAULT_CONFIG:
                expected[key] = config[key]

        if expected['module_search_paths'] is not self.IGNORE_CONFIG:
            pythonpath_env = expected['pythonpath_env']
            if pythonpath_env is not None:
                paths = pythonpath_env.split(os.path.pathsep)
                expected['module_search_paths'] = [*paths, *expected['module_search_paths']]
            if modify_path_cb is not None:
                expected['module_search_paths'] = expected['module_search_paths'].copy()
                modify_path_cb(expected['module_search_paths'])

        for key in self.COPY_PRE_CONFIG:
            if key not in expected_preconfig:
                expected_preconfig[key] = expected[key]

    def check_pre_config(self, configs, expected):
        pre_config = dict(configs['pre_config'])
        for key, value in list(expected.items()):
            if value is self.IGNORE_CONFIG:
                pre_config.pop(key, None)
                del expected[key]
        self.assertEqual(pre_config, expected)

    def check_config(self, configs, expected):
        config = dict(configs['config'])
        if MS_WINDOWS:
            value = config.get(key := 'program_name')
            if value and isinstance(value, str):
                value = value[:len(value.lower().removesuffix('.exe'))]
                if debug_build(sys.executable):
                    value = value[:len(value.lower().removesuffix('_d'))]
                config[key] = value
        for key, value in list(expected.items()):
            if value is self.IGNORE_CONFIG:
                config.pop(key, None)
                del expected[key]
        self.assertEqual(config, expected)

    def check_global_config(self, configs):
        pre_config = configs['pre_config']
        config = configs['config']

        expected = dict(self.DEFAULT_GLOBAL_CONFIG)
        for item in self.COPY_GLOBAL_CONFIG:
            if len(item) == 3:
                global_key, core_key, opposite = item
                expected[global_key] = 0 if config[core_key] else 1
            else:
                global_key, core_key = item
                expected[global_key] = config[core_key]
        for item in self.COPY_GLOBAL_PRE_CONFIG:
            if len(item) == 3:
                global_key, core_key, opposite = item
                expected[global_key] = 0 if pre_config[core_key] else 1
            else:
                global_key, core_key = item
                expected[global_key] = pre_config[core_key]

        self.assertEqual(configs['global_config'], expected)

    def check_all_configs(self, testname, expected_config=None,
                          expected_preconfig=None,
                          modify_path_cb=None,
                          stderr=None, *, api, preconfig_api=None,
                          env=None, ignore_stderr=False, cwd=None):
        new_env = remove_python_envvars()
        if env is not None:
            new_env.update(env)
        env = new_env

        if preconfig_api is None:
            preconfig_api = api
        if preconfig_api == API_ISOLATED:
            default_preconfig = self.PRE_CONFIG_ISOLATED
        elif preconfig_api == API_PYTHON:
            default_preconfig = self.PRE_CONFIG_PYTHON
        else:
            default_preconfig = self.PRE_CONFIG_COMPAT
        if expected_preconfig is None:
            expected_preconfig = {}
        expected_preconfig = dict(default_preconfig, **expected_preconfig)

        if expected_config is None:
            expected_config = {}

        if api == API_PYTHON:
            default_config = self.CONFIG_PYTHON
        elif api == API_ISOLATED:
            default_config = self.CONFIG_ISOLATED
        else:
            default_config = self.CONFIG_COMPAT
        expected_config = dict(default_config, **expected_config)

        self.get_expected_config(expected_preconfig,
                                 expected_config,
                                 env,
                                 api, modify_path_cb)

        out, err = self.run_embedded_interpreter(testname,
                                                 env=env, cwd=cwd)
        if stderr is None and not expected_config['verbose']:
            stderr = ""
        if stderr is not None and not ignore_stderr:
            self.assertEqual(err.rstrip(), stderr)
        try:
            configs = json.loads(out)
        except json.JSONDecodeError:
            self.fail(f"fail to decode stdout: {out!r}")

        self.check_pre_config(configs, expected_preconfig)
        self.check_config(configs, expected_config)
        self.check_global_config(configs)
        return configs

    def test_init_default_config(self):
        self.check_all_configs("test_init_initialize_config", api=API_COMPAT)

    def test_preinit_compat_config(self):
        self.check_all_configs("test_preinit_compat_config", api=API_COMPAT)

    def test_init_compat_config(self):
        self.check_all_configs("test_init_compat_config", api=API_COMPAT)

    def test_init_global_config(self):
        preconfig = {
            'utf8_mode': 1,
        }
        config = {
            'program_name': './globalvar',
            'site_import': 0,
            'bytes_warning': 1,
            'warnoptions': ['default::BytesWarning'],
            'inspect': 1,
            'interactive': 1,
            'optimization_level': 2,
            'write_bytecode': 0,
            'verbose': 1,
            'quiet': 1,
            'buffered_stdio': 0,

            'user_site_directory': 0,
            'pathconfig_warnings': 0,
        }
        self.check_all_configs("test_init_global_config", config, preconfig,
                               api=API_COMPAT)

    def test_init_from_config(self):
        preconfig = {
            'allocator': PYMEM_ALLOCATOR_MALLOC,
            'utf8_mode': 1,
        }
        config = {
            'install_signal_handlers': 0,
            'use_hash_seed': 1,
            'hash_seed': 123,
            'tracemalloc': 2,
            'perf_profiling': 0,
            'import_time': 1,
            'code_debug_ranges': 0,
            'show_ref_count': 1,
            'malloc_stats': 1,

            'stdio_encoding': 'iso8859-1',
            'stdio_errors': 'replace',

            'pycache_prefix': 'conf_pycache_prefix',
            'program_name': './conf_program_name',
            'argv': ['-c', 'arg2'],
            'orig_argv': ['python3',
                          '-W', 'cmdline_warnoption',
                          '-X', 'cmdline_xoption',
                          '-c', 'pass',
                          'arg2'],
            'parse_argv': 2,
            'xoptions': [
                'config_xoption1=3',
                'config_xoption2=',
                'config_xoption3',
                'cmdline_xoption',
            ],
            'warnoptions': [
                'cmdline_warnoption',
                'default::BytesWarning',
                'config_warnoption',
            ],
            'run_command': 'pass\n',

            'site_import': 0,
            'bytes_warning': 1,
            'inspect': 1,
            'interactive': 1,
            'optimization_level': 2,
            'write_bytecode': 0,
            'verbose': 1,
            'quiet': 1,
            'configure_c_stdio': 1,
            'buffered_stdio': 0,
            'user_site_directory': 0,
            'faulthandler': 1,
            'platlibdir': 'my_platlibdir',
            'module_search_paths': self.IGNORE_CONFIG,
            'safe_path': 1,
            'int_max_str_digits': 31337,
            'cpu_count': 4321,

            'check_hash_pycs_mode': 'always',
            'pathconfig_warnings': 0,
        }
        if Py_STATS:
            config['_pystats'] = 1
        self.check_all_configs("test_init_from_config", config, preconfig,
                               api=API_COMPAT)

    def test_init_compat_env(self):
        preconfig = {
            'allocator': PYMEM_ALLOCATOR_MALLOC,
        }
        config = {
            'use_hash_seed': 1,
            'hash_seed': 42,
            'tracemalloc': 2,
            'perf_profiling': 0,
            'import_time': 1,
            'code_debug_ranges': 0,
            'malloc_stats': 1,
            'inspect': 1,
            'optimization_level': 2,
            'pythonpath_env': '/my/path',
            'pycache_prefix': 'env_pycache_prefix',
            'write_bytecode': 0,
            'verbose': 1,
            'buffered_stdio': 0,
            'stdio_encoding': 'iso8859-1',
            'stdio_errors': 'replace',
            'user_site_directory': 0,
            'faulthandler': 1,
            'warnoptions': ['EnvVar'],
            'platlibdir': 'env_platlibdir',
            'module_search_paths': self.IGNORE_CONFIG,
            'safe_path': 1,
            'int_max_str_digits': 4567,
        }
        if Py_STATS:
            config['_pystats'] = 1
        self.check_all_configs("test_init_compat_env", config, preconfig,
                               api=API_COMPAT)

    def test_init_python_env(self):
        preconfig = {
            'allocator': PYMEM_ALLOCATOR_MALLOC,
            'utf8_mode': 1,
        }
        config = {
            'use_hash_seed': 1,
            'hash_seed': 42,
            'tracemalloc': 2,
            'perf_profiling': 0,
            'import_time': 1,
            'code_debug_ranges': 0,
            'malloc_stats': 1,
            'inspect': 1,
            'optimization_level': 2,
            'pythonpath_env': '/my/path',
            'pycache_prefix': 'env_pycache_prefix',
            'write_bytecode': 0,
            'verbose': 1,
            'buffered_stdio': 0,
            'stdio_encoding': 'iso8859-1',
            'stdio_errors': 'replace',
            'user_site_directory': 0,
            'faulthandler': 1,
            'warnoptions': ['EnvVar'],
            'platlibdir': 'env_platlibdir',
            'module_search_paths': self.IGNORE_CONFIG,
            'safe_path': 1,
            'int_max_str_digits': 4567,
        }
        if Py_STATS:
            config['_pystats'] = 1
        self.check_all_configs("test_init_python_env", config, preconfig,
                               api=API_PYTHON)

    def test_init_env_dev_mode(self):
        preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
        config = dict(dev_mode=1,
                      faulthandler=1,
                      warnoptions=['default'])
        self.check_all_configs("test_init_env_dev_mode", config, preconfig,
                               api=API_COMPAT)

    def test_init_env_dev_mode_alloc(self):
        preconfig = dict(allocator=PYMEM_ALLOCATOR_MALLOC)
        config = dict(dev_mode=1,
                      faulthandler=1,
                      warnoptions=['default'])
        self.check_all_configs("test_init_env_dev_mode_alloc", config, preconfig,
                               api=API_COMPAT)

    def test_init_dev_mode(self):
        preconfig = {
            'allocator': PYMEM_ALLOCATOR_DEBUG,
        }
        config = {
            'faulthandler': 1,
            'dev_mode': 1,
            'warnoptions': ['default'],
        }
        self.check_all_configs("test_init_dev_mode", config, preconfig,
                               api=API_PYTHON)

    def test_preinit_parse_argv(self):
        
        
        preconfig = {
            'allocator': PYMEM_ALLOCATOR_DEBUG,
        }
        config = {
            'argv': ['script.py'],
            'orig_argv': ['python3', '-X', 'dev', '-P', 'script.py'],
            'run_filename': os.path.abspath('script.py'),
            'dev_mode': 1,
            'faulthandler': 1,
            'warnoptions': ['default'],
            'xoptions': ['dev'],
            'safe_path': 1,
        }
        self.check_all_configs("test_preinit_parse_argv", config, preconfig,
                               api=API_PYTHON)

    def test_preinit_dont_parse_argv(self):
        
        preconfig = {
            'isolated': 0,
        }
        argv = ["python3",
               "-E", "-I", "-P",
               "-X", "dev",
               "-X", "utf8",
               "script.py"]
        config = {
            'argv': argv,
            'orig_argv': argv,
            'isolated': 0,
        }
        self.check_all_configs("test_preinit_dont_parse_argv", config, preconfig,
                               api=API_ISOLATED)

    def test_init_isolated_flag(self):
        config = {
            'isolated': 1,
            'safe_path': 1,
            'use_environment': 0,
            'user_site_directory': 0,
        }
        self.check_all_configs("test_init_isolated_flag", config, api=API_PYTHON)

    def test_preinit_isolated1(self):
        
        config = {
            'isolated': 1,
            'safe_path': 1,
            'use_environment': 0,
            'user_site_directory': 0,
        }
        self.check_all_configs("test_preinit_isolated1", config, api=API_COMPAT)

    def test_preinit_isolated2(self):
        
        config = {
            'isolated': 1,
            'safe_path': 1,
            'use_environment': 0,
            'user_site_directory': 0,
        }
        self.check_all_configs("test_preinit_isolated2", config, api=API_COMPAT)

    def test_preinit_isolated_config(self):
        self.check_all_configs("test_preinit_isolated_config", api=API_ISOLATED)

    def test_init_isolated_config(self):
        self.check_all_configs("test_init_isolated_config", api=API_ISOLATED)

    def test_preinit_python_config(self):
        self.check_all_configs("test_preinit_python_config", api=API_PYTHON)

    def test_init_python_config(self):
        self.check_all_configs("test_init_python_config", api=API_PYTHON)

    def test_init_dont_configure_locale(self):
        
        preconfig = {
            'configure_locale': 0,
            'coerce_c_locale': 0,
        }
        self.check_all_configs("test_init_dont_configure_locale", {}, preconfig,
                               api=API_PYTHON)

    @unittest.skip('as of 3.11 this test no longer works because '
                   'path calculations do not occur on read')
    def test_init_read_set(self):
        config = {
            'program_name': './init_read_set',
            'executable': 'my_executable',
            'base_executable': 'my_executable',
        }
        def modify_path(path):
            path.insert(1, "test_path_insert1")
            path.append("test_path_append")
        self.check_all_configs("test_init_read_set", config,
                               api=API_PYTHON,
                               modify_path_cb=modify_path)

    def test_init_sys_add(self):
        config = {
            'faulthandler': 1,
            'xoptions': [
                'config_xoption',
                'cmdline_xoption',
                'sysadd_xoption',
                'faulthandler',
            ],
            'warnoptions': [
                'ignore:::cmdline_warnoption',
                'ignore:::sysadd_warnoption',
                'ignore:::config_warnoption',
            ],
            'orig_argv': ['python3',
                          '-W', 'ignore:::cmdline_warnoption',
                          '-X', 'cmdline_xoption'],
        }
        self.check_all_configs("test_init_sys_add", config, api=API_PYTHON)

    def test_init_run_main(self):
        code = ('import _testinternalcapi, json; '
                'print(json.dumps(_testinternalcapi.get_configs()))')
        config = {
            'argv': ['-c', 'arg2'],
            'orig_argv': ['python3', '-c', code, 'arg2'],
            'program_name': './python3',
            'run_command': code + '\n',
            'parse_argv': 2,
            'sys_path_0': '',
        }
        self.check_all_configs("test_init_run_main", config, api=API_PYTHON)

    def test_init_main(self):
        code = ('import _testinternalcapi, json; '
                'print(json.dumps(_testinternalcapi.get_configs()))')
        config = {
            'argv': ['-c', 'arg2'],
            'orig_argv': ['python3',
                          '-c', code,
                          'arg2'],
            'program_name': './python3',
            'run_command': code + '\n',
            'parse_argv': 2,
            '_init_main': 0,
            'sys_path_0': '',
        }
        self.check_all_configs("test_init_main", config,
                               api=API_PYTHON,
                               stderr="Run Python code before _Py_InitializeMain")

    def test_init_parse_argv(self):
        config = {
            'parse_argv': 2,
            'argv': ['-c', 'arg1', '-v', 'arg3'],
            'orig_argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
            'program_name': './argv0',
            'run_command': 'pass\n',
            'use_environment': 0,
        }
        self.check_all_configs("test_init_parse_argv", config, api=API_PYTHON)

    def test_init_dont_parse_argv(self):
        pre_config = {
            'parse_argv': 0,
        }
        config = {
            'parse_argv': 0,
            'argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
            'orig_argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'],
            'program_name': './argv0',
        }
        self.check_all_configs("test_init_dont_parse_argv", config, pre_config,
                               api=API_PYTHON)

    def default_program_name(self, config):
        if MS_WINDOWS:
            program_name = 'python'
            executable = self.test_exe
        else:
            program_name = 'python3'
            if MACOS:
                executable = self.test_exe
            else:
                executable = shutil.which(program_name) or ''
        config.update({
            'program_name': program_name,
            'base_executable': executable,
            'executable': executable,
        })

    def test_init_setpath(self):
        
        config = self._get_expected_config()
        paths = config['config']['module_search_paths']

        config = {
            'module_search_paths': paths,
            'prefix': '',
            'base_prefix': '',
            'exec_prefix': '',
            'base_exec_prefix': '',
             
             
            'stdlib_dir': '',
        }
        self.default_program_name(config)
        env = {'TESTPATH': os.path.pathsep.join(paths)}

        self.check_all_configs("test_init_setpath", config,
                               api=API_COMPAT, env=env,
                               ignore_stderr=True)

    def test_init_setpath_config(self):
        
        config = self._get_expected_config()
        paths = config['config']['module_search_paths']

        config = {
            
            'module_search_paths': paths,
            'prefix': '',
            'base_prefix': '',
            'exec_prefix': '',
            'base_exec_prefix': '',
             
             
            'stdlib_dir': '',
            'use_frozen_modules': not support.Py_DEBUG,
            
            'program_name': 'conf_program_name',
            'base_executable': 'conf_executable',
            'executable': 'conf_executable',
        }
        env = {'TESTPATH': os.path.pathsep.join(paths)}
        self.check_all_configs("test_init_setpath_config", config,
                               api=API_PYTHON, env=env, ignore_stderr=True)

    def module_search_paths(self, prefix=None, exec_prefix=None):
        config = self._get_expected_config()
        if prefix is None:
            prefix = config['config']['prefix']
        if exec_prefix is None:
            exec_prefix = config['config']['prefix']
        if MS_WINDOWS:
            return config['config']['module_search_paths']
        else:
            ver = sys.version_info
            return [
                os.path.join(prefix, sys.platlibdir,
                             f'python{ver.major}{ver.minor}.zip'),
                os.path.join(prefix, sys.platlibdir,
                             f'python{ver.major}.{ver.minor}'),
                os.path.join(exec_prefix, sys.platlibdir,
                             f'python{ver.major}.{ver.minor}', 'lib-dynload'),
            ]

    @contextlib.contextmanager
    def tmpdir_with_python(self, subdir=None):
        
        with tempfile.TemporaryDirectory() as tmpdir:
            
            
            
            tmpdir = os.path.realpath(tmpdir)
            if subdir:
                tmpdir = os.path.normpath(os.path.join(tmpdir, subdir))
                os.makedirs(tmpdir)

            if MS_WINDOWS:
                
                import fnmatch
                exedir = os.path.dirname(self.test_exe)
                for f in os.listdir(exedir):
                    if fnmatch.fnmatch(f, '*.dll'):
                        shutil.copyfile(os.path.join(exedir, f), os.path.join(tmpdir, f))

            
            exec_copy = os.path.join(tmpdir, os.path.basename(self.test_exe))
            shutil.copyfile(self.test_exe, exec_copy)
            shutil.copystat(self.test_exe, exec_copy)
            self.test_exe = exec_copy

            yield tmpdir

    def test_init_setpythonhome(self):
        
        config = self._get_expected_config()
        paths = config['config']['module_search_paths']
        paths_str = os.path.pathsep.join(paths)

        for path in paths:
            if not os.path.isdir(path):
                continue
            if os.path.exists(os.path.join(path, 'os.py')):
                home = os.path.dirname(path)
                break
        else:
            self.fail(f"Unable to find home in {paths!r}")

        prefix = exec_prefix = home
        if MS_WINDOWS:
            stdlib = os.path.join(home, "Lib")
            
            
            expected_paths = [paths[0], os.path.join(home, 'DLLs'), stdlib]
        else:
            version = f'{sys.version_info.major}.{sys.version_info.minor}'
            stdlib = os.path.join(home, sys.platlibdir, f'python{version}')
            expected_paths = self.module_search_paths(prefix=home, exec_prefix=home)

        config = {
            'home': home,
            'module_search_paths': expected_paths,
            'prefix': prefix,
            'base_prefix': prefix,
            'exec_prefix': exec_prefix,
            'base_exec_prefix': exec_prefix,
            'pythonpath_env': paths_str,
            'stdlib_dir': stdlib,
        }
        self.default_program_name(config)
        env = {'TESTHOME': home, 'PYTHONPATH': paths_str}
        self.check_all_configs("test_init_setpythonhome", config,
                               api=API_COMPAT, env=env)

    def test_init_is_python_build_with_home(self):
        
        config = self._get_expected_config()
        paths = config['config']['module_search_paths']
        paths_str = os.path.pathsep.join(paths)

        for path in paths:
            if not os.path.isdir(path):
                continue
            if os.path.exists(os.path.join(path, 'os.py')):
                home = os.path.dirname(path)
                break
        else:
            self.fail(f"Unable to find home in {paths!r}")

        prefix = exec_prefix = home
        if MS_WINDOWS:
            stdlib = os.path.join(home, "Lib")
            
            
            expected_paths = [paths[0], os.path.join(home, 'DLLs'), stdlib]
        else:
            version = f'{sys.version_info.major}.{sys.version_info.minor}'
            stdlib = os.path.join(home, sys.platlibdir, f'python{version}')
            expected_paths = self.module_search_paths(prefix=home, exec_prefix=home)

        config = {
            'home': home,
            'module_search_paths': expected_paths,
            'prefix': prefix,
            'base_prefix': prefix,
            'exec_prefix': exec_prefix,
            'base_exec_prefix': exec_prefix,
            'pythonpath_env': paths_str,
            'stdlib_dir': stdlib,
        }
        
        env = {'TESTHOME': home, 'PYTHONPATH': paths_str}

        env['NEGATIVE_ISPYTHONBUILD'] = '1'
        config['_is_python_build'] = 0
        self.check_all_configs("test_init_is_python_build", config,
                               api=API_COMPAT, env=env)

        env['NEGATIVE_ISPYTHONBUILD'] = '0'
        config['_is_python_build'] = 1
        exedir = os.path.dirname(sys.executable)
        with open(os.path.join(exedir, 'pybuilddir.txt'), encoding='utf8') as f:
            expected_paths[1 if MS_WINDOWS else 2] = os.path.normpath(
                os.path.join(exedir, f'{f.read()}\n$'.splitlines()[0]))
        if not MS_WINDOWS:
            
            prefix = exec_prefix = sys.prefix
            
            expected_paths[0] = self.module_search_paths(prefix=prefix)[0]
            config.update(prefix=prefix, base_prefix=prefix,
                          exec_prefix=exec_prefix, base_exec_prefix=exec_prefix)
        self.check_all_configs("test_init_is_python_build", config,
                               api=API_COMPAT, env=env)

    def copy_paths_by_env(self, config):
        all_configs = self._get_expected_config()
        paths = all_configs['config']['module_search_paths']
        paths_str = os.path.pathsep.join(paths)
        config['pythonpath_env'] = paths_str
        env = {'PYTHONPATH': paths_str}
        return env

    @unittest.skipIf(MS_WINDOWS, 'See test_init_pybuilddir_win32')
    def test_init_pybuilddir(self):
        

        with self.tmpdir_with_python() as tmpdir:
            
            
            vpath = sysconfig.get_config_var("VPATH") or ''
            subdir = 'libdir'
            libdir = os.path.join(tmpdir, subdir)
            
            stdlibdir = os.path.normpath(os.path.join(tmpdir, vpath, 'Lib'))
            os.mkdir(libdir)

            filename = os.path.join(tmpdir, 'pybuilddir.txt')
            with open(filename, "w", encoding="utf8") as fp:
                fp.write(subdir)

            module_search_paths = self.module_search_paths()
            module_search_paths[-2] = stdlibdir
            module_search_paths[-1] = libdir

            executable = self.test_exe
            config = {
                'base_exec_prefix': sysconfig.get_config_var("exec_prefix"),
                'base_prefix': sysconfig.get_config_var("prefix"),
                'base_executable': executable,
                'executable': executable,
                'module_search_paths': module_search_paths,
                'stdlib_dir': stdlibdir,
            }
            env = self.copy_paths_by_env(config)
            self.check_all_configs("test_init_compat_config", config,
                                   api=API_COMPAT, env=env,
                                   ignore_stderr=True, cwd=tmpdir)

    @unittest.skipUnless(MS_WINDOWS, 'See test_init_pybuilddir')
    def test_init_pybuilddir_win32(self):
        

        vpath = sysconfig.get_config_var("VPATH")
        subdir = r'PCbuild\arch'
        if os.path.normpath(vpath).count(os.sep) == 2:
            subdir = os.path.join(subdir, 'instrumented')

        with self.tmpdir_with_python(subdir) as tmpdir:
            
            prefix = os.path.normpath(os.path.join(tmpdir, vpath))
            
            stdlibdir = os.path.normpath(os.path.join(tmpdir, vpath, 'Lib'))

            filename = os.path.join(tmpdir, 'pybuilddir.txt')
            with open(filename, "w", encoding="utf8") as fp:
                fp.write(tmpdir)

            module_search_paths = self.module_search_paths()
            module_search_paths[-3] = os.path.join(tmpdir, os.path.basename(module_search_paths[-3]))
            module_search_paths[-2] = tmpdir
            module_search_paths[-1] = stdlibdir

            executable = self.test_exe
            config = {
                'base_exec_prefix': prefix,
                'base_prefix': prefix,
                'base_executable': executable,
                'executable': executable,
                'prefix': prefix,
                'exec_prefix': prefix,
                'module_search_paths': module_search_paths,
                'stdlib_dir': stdlibdir,
            }
            env = self.copy_paths_by_env(config)
            self.check_all_configs("test_init_compat_config", config,
                                   api=API_COMPAT, env=env,
                                   ignore_stderr=False, cwd=tmpdir)

    def test_init_pyvenv_cfg(self):
        

        with self.tmpdir_with_python() as tmpdir, \
             tempfile.TemporaryDirectory() as pyvenv_home:
            ver = sys.version_info

            if not MS_WINDOWS:
                lib_dynload = os.path.join(pyvenv_home,
                                           sys.platlibdir,
                                           f'python{ver.major}.{ver.minor}',
                                           'lib-dynload')
                os.makedirs(lib_dynload)
            else:
                lib_folder = os.path.join(pyvenv_home, 'Lib')
                os.makedirs(lib_folder)
                
                shutil.copyfile(
                    os.path.join(support.STDLIB_DIR, 'os.py'),
                    os.path.join(lib_folder, 'os.py'),
                )

            filename = os.path.join(tmpdir, 'pyvenv.cfg')
            with open(filename, "w", encoding="utf8") as fp:
                print("home = %s" % pyvenv_home, file=fp)
                print("include-system-site-packages = false", file=fp)

            paths = self.module_search_paths()
            if not MS_WINDOWS:
                paths[-1] = lib_dynload
            else:
                paths = [
                    os.path.join(tmpdir, os.path.basename(paths[0])),
                    pyvenv_home,
                    os.path.join(pyvenv_home, "Lib"),
                ]

            executable = self.test_exe
            base_executable = os.path.join(pyvenv_home, os.path.basename(executable))
            exec_prefix = pyvenv_home
            config = {
                'base_prefix': sysconfig.get_config_var("prefix"),
                'base_exec_prefix': exec_prefix,
                'exec_prefix': exec_prefix,
                'base_executable': base_executable,
                'executable': executable,
                'module_search_paths': paths,
            }
            if MS_WINDOWS:
                config['base_prefix'] = pyvenv_home
                config['prefix'] = pyvenv_home
                config['stdlib_dir'] = os.path.join(pyvenv_home, 'Lib')
                config['use_frozen_modules'] = int(not support.Py_DEBUG)
            else:
                
                
                config['stdlib_dir'] = self.IGNORE_CONFIG
                config['use_frozen_modules'] = int(not support.Py_DEBUG)

            env = self.copy_paths_by_env(config)
            self.check_all_configs("test_init_compat_config", config,
                                   api=API_COMPAT, env=env,
                                   ignore_stderr=True, cwd=tmpdir)

    @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
    def test_getpath_abspath_win32(self):
        
        
        
        CASES = [
            ("C:/a. . .",  "C:\\a. . ."),
            ("C:\\a. . .", "C:\\a. . ."),
            ("\\\\?\\C:////a////b. . .", "\\\\?\\C:\\a\\b. . ."),
            ("//a/b/c. . .", "\\\\a\\b\\c. . ."),
            ("\\\\a\\b\\c. . .", "\\\\a\\b\\c. . ."),
            ("a. . .", f"{os.getcwd()}\\a"),  
        ]
        out, err = self.run_embedded_interpreter(
            "test_init_initialize_config",
            env={**remove_python_envvars(),
                 "PYTHONPATH": os.path.pathsep.join(c[0] for c in CASES)}
        )
        self.assertEqual(err, "")
        try:
            out = json.loads(out)
        except json.JSONDecodeError:
            self.fail(f"fail to decode stdout: {out!r}")

        results = out['config']["module_search_paths"]
        for (_, expected), result in zip(CASES, results):
            self.assertEqual(result, expected)

    def test_global_pathconfig(self):
        
        
        
        
        
        
        
        
        
        
        
        ctypes = import_helper.import_module('ctypes')
        _testinternalcapi = import_helper.import_module('_testinternalcapi')

        def get_func(name):
            func = getattr(ctypes.pythonapi, name)
            func.argtypes = ()
            func.restype = ctypes.c_wchar_p
            return func

        Py_GetPath = get_func('Py_GetPath')
        Py_GetPrefix = get_func('Py_GetPrefix')
        Py_GetExecPrefix = get_func('Py_GetExecPrefix')
        Py_GetProgramName = get_func('Py_GetProgramName')
        Py_GetProgramFullPath = get_func('Py_GetProgramFullPath')
        Py_GetPythonHome = get_func('Py_GetPythonHome')

        config = _testinternalcapi.get_configs()['config']

        self.assertEqual(Py_GetPath().split(os.path.pathsep),
                         config['module_search_paths'])
        self.assertEqual(Py_GetPrefix(), config['prefix'])
        self.assertEqual(Py_GetExecPrefix(), config['exec_prefix'])
        self.assertEqual(Py_GetProgramName(), config['program_name'])
        self.assertEqual(Py_GetProgramFullPath(), config['executable'])
        self.assertEqual(Py_GetPythonHome(), config['home'])

    def test_init_warnoptions(self):
        
        warnoptions = [
            'ignore:::PyConfig_Insert0',      
            'default',                        
            'ignore:::env1',                  
            'ignore:::env2',                  
            'ignore:::cmdline1',              
            'ignore:::cmdline2',              
            'default::BytesWarning',          
            'ignore:::PySys_AddWarnOption1',  
            'ignore:::PySys_AddWarnOption2',  
            'ignore:::PyConfig_BeforeRead',   
            'ignore:::PyConfig_AfterRead']    
        preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
        config = {
            'dev_mode': 1,
            'faulthandler': 1,
            'bytes_warning': 1,
            'warnoptions': warnoptions,
            'orig_argv': ['python3',
                          '-Wignore:::cmdline1',
                          '-Wignore:::cmdline2'],
        }
        self.check_all_configs("test_init_warnoptions", config, preconfig,
                               api=API_PYTHON)

    def test_init_set_config(self):
        config = {
            '_init_main': 0,
            'bytes_warning': 2,
            'warnoptions': ['error::BytesWarning'],
        }
        self.check_all_configs("test_init_set_config", config,
                               api=API_ISOLATED)

    def test_get_argc_argv(self):
        self.run_embedded_interpreter("test_get_argc_argv")
        

    def test_init_use_frozen_modules(self):
        tests = {
            ('=on', 1),
            ('=off', 0),
            ('=', 1),
            ('', 1),
        }
        for raw, expected in tests:
            optval = f'frozen_modules{raw}'
            config = {
                'parse_argv': 2,
                'argv': ['-c'],
                'orig_argv': ['./argv0', '-X', optval, '-c', 'pass'],
                'program_name': './argv0',
                'run_command': 'pass\n',
                'use_environment': 1,
                'xoptions': [optval],
                'use_frozen_modules': expected,
            }
            env = {'TESTFROZEN': raw[1:]} if raw else None
            with self.subTest(repr(raw)):
                self.check_all_configs("test_init_use_frozen_modules", config,
                                       api=API_PYTHON, env=env)

    def test_init_main_interpreter_settings(self):
        OBMALLOC = 1<<5
        EXTENSIONS = 1<<8
        THREADS = 1<<10
        DAEMON_THREADS = 1<<11
        FORK = 1<<15
        EXEC = 1<<16
        expected = {
            
            'feature_flags':
                OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS,
            'own_gil': True,
        }
        out, err = self.run_embedded_interpreter(
            'test_init_main_interpreter_settings',
        )
        self.assertEqual(err, '')
        try:
            out = json.loads(out)
        except json.JSONDecodeError:
            self.fail(f'fail to decode stdout: {out!r}')

        self.assertEqual(out, expected)


class SetConfigTests(unittest.TestCase):
    def test_set_config(self):
        
        import_helper.import_module('_testcapi')
        cmd = [sys.executable, '-X', 'utf8', '-I', '-m', 'test._test_embed_set_config']
        proc = subprocess.run(cmd,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              encoding='utf-8', errors='backslashreplace')
        if proc.returncode and support.verbose:
            print(proc.stdout)
            print(proc.stderr)
        self.assertEqual(proc.returncode, 0,
                         (proc.returncode, proc.stdout, proc.stderr))


class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
    def test_open_code_hook(self):
        self.run_embedded_interpreter("test_open_code_hook")

    def test_audit(self):
        self.run_embedded_interpreter("test_audit")

    def test_audit_tuple(self):
        self.run_embedded_interpreter("test_audit_tuple")

    def test_audit_subinterpreter(self):
        self.run_embedded_interpreter("test_audit_subinterpreter")

    def test_audit_run_command(self):
        self.run_embedded_interpreter("test_audit_run_command",
                                      timeout=support.SHORT_TIMEOUT,
                                      returncode=1)

    def test_audit_run_file(self):
        self.run_embedded_interpreter("test_audit_run_file",
                                      timeout=support.SHORT_TIMEOUT,
                                      returncode=1)

    def test_audit_run_interactivehook(self):
        startup = os.path.join(self.oldcwd, os_helper.TESTFN) + ".py"
        with open(startup, "w", encoding="utf-8") as f:
            print("import sys", file=f)
            print("sys.__interactivehook__ = lambda: None", file=f)
        try:
            env = {**remove_python_envvars(), "PYTHONSTARTUP": startup}
            self.run_embedded_interpreter("test_audit_run_interactivehook",
                                          timeout=support.SHORT_TIMEOUT,
                                          returncode=10, env=env)
        finally:
            os.unlink(startup)

    def test_audit_run_startup(self):
        startup = os.path.join(self.oldcwd, os_helper.TESTFN) + ".py"
        with open(startup, "w", encoding="utf-8") as f:
            print("pass", file=f)
        try:
            env = {**remove_python_envvars(), "PYTHONSTARTUP": startup}
            self.run_embedded_interpreter("test_audit_run_startup",
                                          timeout=support.SHORT_TIMEOUT,
                                          returncode=10, env=env)
        finally:
            os.unlink(startup)

    def test_audit_run_stdin(self):
        self.run_embedded_interpreter("test_audit_run_stdin",
                                      timeout=support.SHORT_TIMEOUT,
                                      returncode=1)

    def test_get_incomplete_frame(self):
        self.run_embedded_interpreter("test_get_incomplete_frame")


class MiscTests(EmbeddingTestsMixin, unittest.TestCase):
    def test_unicode_id_init(self):
        
        
        self.run_embedded_interpreter("test_unicode_id_init")

    
    @unittest.skipIf(os.name == 'nt',
                     'Py_FrozenMain is not exported on Windows')
    def test_frozenmain(self):
        env = dict(os.environ)
        env['PYTHONUNBUFFERED'] = '1'
        out, err = self.run_embedded_interpreter("test_frozenmain", env=env)
        executable = os.path.realpath('./argv0')
        expected = textwrap.dedent(f).lstrip()
        self.assertEqual(out, expected)

    @unittest.skipUnless(support.Py_DEBUG,
                         '-X showrefcount requires a Python debug build')
    def test_no_memleak(self):
        
        tests = (
            ('off', 'pass'),
            ('on', 'pass'),
            ('off', 'import __hello__'),
            ('on', 'import __hello__'),
        )
        for flag, stmt in tests:
            xopt = f"frozen_modules={flag}"
            cmd = [sys.executable, "-I", "-X", "showrefcount", "-X", xopt, "-c", stmt]
            proc = subprocess.run(cmd,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT,
                                  text=True)
            self.assertEqual(proc.returncode, 0)
            out = proc.stdout.rstrip()
            match = re.match(r'^\[(-?\d+) refs, (-?\d+) blocks\]', out)
            if not match:
                self.fail(f"unexpected output: {out!a}")
            refs = int(match.group(1))
            blocks = int(match.group(2))
            with self.subTest(frozen_modules=flag, stmt=stmt):
                self.assertEqual(refs, 0, out)
                self.assertEqual(blocks, 0, out)

    @unittest.skipUnless(support.Py_DEBUG,
                         '-X presite requires a Python debug build')
    def test_presite(self):
        cmd = [sys.executable, "-I", "-X", "presite=test.reperf", "-c", "print('cmd')"]
        proc = subprocess.run(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
        )
        self.assertEqual(proc.returncode, 0)
        out = proc.stdout.strip()
        self.assertIn("10 times sub", out)
        self.assertIn("CPU seconds", out)
        self.assertIn("cmd", out)


class StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase):
    
    
    

    STDOUT_FD = 1

    def create_printer(self, fd):
        ctypes = import_helper.import_module('ctypes')
        PyFile_NewStdPrinter = ctypes.pythonapi.PyFile_NewStdPrinter
        PyFile_NewStdPrinter.argtypes = (ctypes.c_int,)
        PyFile_NewStdPrinter.restype = ctypes.py_object
        return PyFile_NewStdPrinter(fd)

    def test_write(self):
        message = "unicode:\xe9-\u20ac-\udc80!\n"

        stdout_fd = self.STDOUT_FD
        stdout_fd_copy = os.dup(stdout_fd)
        self.addCleanup(os.close, stdout_fd_copy)

        rfd, wfd = os.pipe()
        self.addCleanup(os.close, rfd)
        self.addCleanup(os.close, wfd)
        try:
            
            
            os.dup2(wfd, stdout_fd)

            printer = self.create_printer(stdout_fd)
            printer.write(message)
        finally:
            os.dup2(stdout_fd_copy, stdout_fd)

        data = os.read(rfd, 100)
        self.assertEqual(data, message.encode('utf8', 'backslashreplace'))

    def test_methods(self):
        fd = self.STDOUT_FD
        printer = self.create_printer(fd)
        self.assertEqual(printer.fileno(), fd)
        self.assertEqual(printer.isatty(), os.isatty(fd))
        printer.flush()  
        printer.close()  

    def test_disallow_instantiation(self):
        fd = self.STDOUT_FD
        printer = self.create_printer(fd)
        support.check_disallow_instantiation(self, type(printer))


if __name__ == "__main__":
    unittest.main()