tests the attempted automatic coercion of the c locale to a utf8 locale set the list of ways we expect to be able to ask for the c locale set our expectation for the default encoding used in the c locale for the filesystem encoding and the standard streams set our expectation for the default locale used when none is specified apply some platform dependent overrides android defaults to using utf8 for all system interfaces linux distros typically alias the posix locale directly to the c locale todo once https bugs python orgissue30672 is addressed we ll be able to check this case unconditionally aix uses iso88591 in the c locale other nix platforms use ascii fs encoding is utf8 on macos cygwin defaults to using c utf8 todo work out a robust dynamic test for this that doesn t rely on cpython s own locale handling machinery vxworks defaults to using utf8 for all system interfaces note that the above expectations are still wrong in some cases such as windows when pythonlegacywindowsfsencoding is set any platform other than aix that uses latin1 in the c locale any linux distro where posix isn t a simple alias for the c locale any linux distro where the default locale is something other than c options for dealing with this don t set the pycoerceclocale preprocessor definition on such platforms e g it isn t set on windows fix the test expectations to match the actual platform behaviour in order to get the warning messages to match up as expected the candidate order here must much the target locale order in pythonpylifecycle c there s no reliable crossplatform way of checking locale alias lists so the only way of knowing which of these locales will work is to try them with locale setlocale we do that in a subprocess in setupmodule below to avoid altering the locale of the test runner if the relevant locale module attributes exist and we re not on a platform where we expect it to always succeed we also check that locale nllanginfolocale codeset works as if it fails the interpreter will skip locale coercion for that particular target locale if there s no valid codeset we expect coercion to be skipped xxx ncoghlan using json for child state reporting may be less fragile returns expected child process details for a given encoding stream streamencoding stdin and stdout should use surrogateescape either because the coercion triggered or because the c locale was detected streaminfo 2stream formatsurrogateescape stderr should always use backslashreplace streaminfo appendstream formatbackslashreplace expectedlang envvars getlang not set if coercionexpected expectedlcctype clicoerciontarget else expectedlcctype envvars getlcctype not set expectedlcall envvars getlcall not set envinfo expectedlang expectedlcctype expectedlcall return dictclsfsencoding streaminfo envinfo asdict classmethod def getchilddetailscls envvars result pycmd runpythonuntilend x utf80 c cls childprocessscript envvars if not result rc 0 result failpycmd all subprocess outputs in this test case should be pure ascii stdoutlines result out decodeascii splitlines childencodingdetails dictclsstdoutlines asdict stderrlines result err decodeascii rstrip splitlines return childencodingdetails stderrlines details of the shared library warning emitted at runtime legacylocalewarning python runtime initialized with lcctypec a locale with default ascii encoding which may cause unicode compatibility problems using c utf8 c utf8 or utf8 if available as alternative unicodecompatible locales is recommended details of the cli locale coercion warning emitted at runtime clicoercionwarningfmt python detected lcctypec lcctype coerced to set another locale or pythoncoerceclocale0 to disable this locale coercion behavior availabletargets none clicoerciontarget none clicoercionwarning none def setupmodule global availabletargets global clicoerciontarget global clicoercionwarning if availabletargets is not none initialization already done return availabletargets find the target locales available in the current system for targetlocale in cutf8locales if setlocaleinsubprocesstargetlocale availabletargets appendtargetlocale if availabletargets coercion is expected to use the first available target locale clicoerciontarget availabletargets0 clicoercionwarning clicoercionwarningfmt formatclicoerciontarget if support verbose printfavailabletargets availabletargets r printfexpectedclocaleequivalents expectedclocaleequivalents r printfexpectedclocalestreamencoding expectedclocalestreamencoding r printfexpectedclocalefsencoding expectedclocalefsencoding r printfexpectcoercionindefaultlocale expectcoercionindefaultlocale r printfcutf8locales cutf8locales r printfchecknllanginfocodeset checknllanginfocodeset r class localehandlingtestcaseunittest testcase base class to check expected locale handling behaviour def checkchildencodingdetailsself envvars expectedfsencoding expectedstreamencoding expectedwarnings coercionexpected result encodingdetails getchilddetailsenvvars encodingdetails stderrlines result expecteddetails encodingdetails getexpecteddetails coercionexpected expectedfsencoding expectedstreamencoding envvars self assertequalencodingdetails expecteddetails if expectedwarnings is none expectedwarnings self assertequalstderrlines expectedwarnings class localeconfigurationtestslocalehandlingtestcase test explicit external configuration via the process environment classmethod def setupclasscls this relies on setupmodule having been run so it can t be handled via the unittest skipunless decorator if not availabletargets raise unittest skiptestno cwithutf8 locale available def testexternaltargetlocaleconfigurationself explicitly setting a target locale should give the same behaviour as is seen when implicitly coercing to that target locale self maxdiff none expectedfsencoding utf8 expectedstreamencoding utf8 basevardict lang lcctype lcall pythoncoerceclocale for envvar in lang lcctype for localetoset in availabletargets xxx ncoghlan langutf8 doesn t appear to work as expected so skip that combination for now see https bugs python orgissue30672 for discussion if envvar lang and localetoset utf8 continue with self subtestenvvarenvvar configuredlocalelocaletoset vardict basevardict copy vardictenvvar localetoset self checkchildencodingdetailsvardict expectedfsencoding expectedstreamencoding expectedwarningsnone coercionexpectedfalse support cpythononly unittest skipunlesssysconfig getconfigvarpycoerceclocale c locale coercion disabled at build time class localecoerciontestslocalehandlingtestcase test implicit reconfiguration of the environment during cli startup def checkclocalecoercionself fsencoding streamencoding coerceclocale expectedwarningsnone coercionexpectedtrue extravars self maxdiff none if not availabletargets locale coercion is disabled when there aren t any target locales fsencoding expectedclocalefsencoding streamencoding expectedclocalestreamencoding coercionexpected false if expectedwarnings expectedwarnings legacylocalewarning basevardict lang lcctype lcall pythoncoerceclocale basevardict updateextravars if coerceclocale is not none basevardictpythoncoerceclocale coerceclocale check behaviour for the default locale with self subtestdefaultlocaletrue pythoncoerceclocalecoerceclocale if expectcoercionindefaultlocale expectedwarnings expectedwarnings coercionexpected coercionexpected else expectedwarnings none coercionexpected false on android clicoercionwarning is not printed when all the locale environment variables are undefined or empty when this code path is run with environ lcall c then legacylocalewarning is printed if support isandroid and expectedwarnings clicoercionwarning expectedwarnings none self checkchildencodingdetailsbasevardict fsencoding streamencoding expectedwarnings coercionexpected check behaviour for explicitly configured locales for localetoset in expectedclocaleequivalents for envvar in lang lcctype with self subtestenvvarenvvar nominallocalelocaletoset pythoncoerceclocalecoerceclocale vardict basevardict copy vardictenvvar localetoset check behaviour on successful coercion self checkchildencodingdetailsvardict fsencoding streamencoding expectedwarnings coercionexpected def testpythoncoerceclocalenotsetself this should coerce to the first available target locale by default self checkclocalecoercionutf8 utf8 coerceclocalenone def testpythoncoerceclocalenotzeroself any string other than 0 is considered set for our purposes and hence should result in the locale coercion being enabled for setting in 1 true false self checkclocalecoercionutf8 utf8 coerceclocalesetting def testpythoncoerceclocalesettowarnself pythoncoerceclocalewarn enables runtime warnings for legacy locales self checkclocalecoercionutf8 utf8 coerceclocalewarn expectedwarningsclicoercionwarning def testpythoncoerceclocalesettozeroself the setting 0 should result in the locale coercion being disabled self checkclocalecoercionexpectedclocalefsencoding expectedclocalestreamencoding coerceclocale0 coercionexpectedfalse setting lcallc shouldn t make any difference to the behaviour self checkclocalecoercionexpectedclocalefsencoding expectedclocalestreamencoding coerceclocale0 lcallc coercionexpectedfalse def testlcallsettocself setting lcall should render the locale coercion ineffective self checkclocalecoercionexpectedclocalefsencoding expectedclocalestreamencoding coerceclocalenone lcallc coercionexpectedfalse and result in a warning about a lack of locale compatibility self checkclocalecoercionexpectedclocalefsencoding expectedclocalestreamencoding coerceclocalewarn lcallc expectedwarningslegacylocalewarning coercionexpectedfalse def testpythoncoerceclocalesettooneself skip the test if the lcctype locale is c or coerced oldloc locale setlocalelocale lcctype none self addcleanuplocale setlocale locale lcctype oldloc try loc locale setlocalelocale lcctype except locale error as e self skipteststre if loc c self skiptesttest requires lcctype locale different than c if loc in targetlocales self skiptestcoerced lcctype locale s loc bpo35336 pythoncoerceclocale1 must not coerce the lcctype locale if it s not equal to c code import locale printlocale setlocalelocale lcctype none env dictos environ pythoncoerceclocale 1 cmd subprocess runsys executable c code stdoutsubprocess pipe envenv texttrue self assertequalcmd stdout rstrip loc def teardownmodule support reapchildren if name main unittest main tests the attempted automatic coercion of the c locale to a utf 8 locale set the list of ways we expect to be able to ask for the c locale set our expectation for the default encoding used in the c locale for the filesystem encoding and the standard streams set our expectation for the default locale used when none is specified apply some platform dependent overrides android defaults to using utf 8 for all system interfaces linux distros typically alias the posix locale directly to the c locale todo once https bugs python org issue30672 is addressed we ll be able to check this case unconditionally aix uses iso8859 1 in the c locale other nix platforms use ascii fs encoding is utf 8 on macos cygwin defaults to using c utf 8 todo work out a robust dynamic test for this that doesn t rely on cpython s own locale handling machinery vxworks defaults to using utf 8 for all system interfaces note that the above expectations are still wrong in some cases such as windows when pythonlegacywindowsfsencoding is set any platform other than aix that uses latin 1 in the c locale any linux distro where posix isn t a simple alias for the c locale any linux distro where the default locale is something other than c options for dealing with this don t set the py_coerce_c_locale preprocessor definition on such platforms e g it isn t set on windows fix the test expectations to match the actual platform behaviour in order to get the warning messages to match up as expected the candidate order here must much the target locale order in python pylifecycle c there s no reliable cross platform way of checking locale alias lists so the only way of knowing which of these locales will work is to try them with locale setlocale we do that in a subprocess in setupmodule below to avoid altering the locale of the test runner if the relevant locale module attributes exist and we re not on a platform where we expect it to always succeed we also check that locale nl_langinfo locale codeset works as if it fails the interpreter will skip locale coercion for that particular target locale if there s no valid codeset we expect coercion to be skipped xxx ncoghlan using json for child state reporting may be less fragile returns expected child process details for a given encoding stdin and stdout should use surrogateescape either because the coercion triggered or because the c locale was detected stderr should always use backslashreplace retrieves fsencoding and standard stream details from a child process returns encoding_details stderr_lines encoding_details encodingdetails for eager decoding stderr_lines result of calling splitlines on the stderr output the child is run in isolated mode if the current interpreter supports that all subprocess outputs in this test case should be pure ascii details of the shared library warning emitted at runtime details of the cli locale coercion warning emitted at runtime initialization already done find the target locales available in the current system coercion is expected to use the first available target locale base class to check expected locale handling behaviour check the c locale handling for the given process environment parameters expected_fs_encoding expected sys getfilesystemencoding result expected_stream_encoding expected encoding for standard streams expected_warning stderr output to expect if any test explicit external configuration via the process environment this relies on setupmodule having been run so it can t be handled via the unittest skipunless decorator explicitly setting a target locale should give the same behaviour as is seen when implicitly coercing to that target locale xxx ncoghlan lang utf 8 doesn t appear to work as expected so skip that combination for now see https bugs python org issue30672 for discussion test implicit reconfiguration of the environment during cli startup check the c locale handling for various configurations parameters fs_encoding expected sys getfilesystemencoding result stream_encoding expected encoding for standard streams coerce_c_locale setting to use for pythoncoerceclocale none don t set the variable at all str the value set in the child s environment expected_warnings expected warning lines on stderr extra_vars additional environment variables to set in subprocess locale coercion is disabled when there aren t any target locales check behaviour for the default locale on android cli_coercion_warning is not printed when all the locale environment variables are undefined or empty when this code path is run with environ lc_all c then legacy_locale_warning is printed check behaviour for explicitly configured locales check behaviour on successful coercion this should coerce to the first available target locale by default any string other than 0 is considered set for our purposes and hence should result in the locale coercion being enabled pythoncoerceclocale warn enables runtime warnings for legacy locales the setting 0 should result in the locale coercion being disabled setting lc_all c shouldn t make any difference to the behaviour setting lc_all should render the locale coercion ineffective and result in a warning about a lack of locale compatibility skip the test if the lc_ctype locale is c or coerced bpo 35336 pythoncoerceclocale 1 must not coerce the lc_ctype locale if it s not equal to c
import locale
import os
import subprocess
import sys
import sysconfig
import unittest
from collections import namedtuple

from test import support
from test.support.script_helper import run_python_until_end



EXPECTED_C_LOCALE_EQUIVALENTS = ["C", "invalid.ascii"]



EXPECTED_C_LOCALE_STREAM_ENCODING = "ascii"
EXPECTED_C_LOCALE_FS_ENCODING = "ascii"


EXPECT_COERCION_IN_DEFAULT_LOCALE = True

TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"]


if sys.platform.startswith("linux"):
    if support.is_android:
        
        EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
        EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
    else:
        
        
        
        
        EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX")
elif sys.platform.startswith("aix"):
    
    EXPECTED_C_LOCALE_STREAM_ENCODING = "iso8859-1"
    EXPECTED_C_LOCALE_FS_ENCODING = "iso8859-1"
elif sys.platform == "darwin":
    
    EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
elif sys.platform == "cygwin":
    
    
    
    EXPECT_COERCION_IN_DEFAULT_LOCALE = False
elif sys.platform == "vxworks":
    
    EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
    EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"














_C_UTF8_LOCALES = ("C.UTF-8", "C.utf8", "UTF-8")










_check_nl_langinfo_CODESET = bool(
    sys.platform not in ("darwin", "linux") and
    hasattr(locale, "nl_langinfo") and
    hasattr(locale, "CODESET")
)

def _set_locale_in_subprocess(locale_name):
    cmd_fmt = "import locale; print(locale.setlocale(locale.LC_CTYPE, '{}'))"
    if _check_nl_langinfo_CODESET:
        
        cmd_fmt += "; import sys; sys.exit(not locale.nl_langinfo(locale.CODESET))"
    cmd = cmd_fmt.format(locale_name)
    result, py_cmd = run_python_until_end("-c", cmd, PYTHONCOERCECLOCALE='')
    return result.rc == 0



_fields = "fsencoding stdin_info stdout_info stderr_info lang lc_ctype lc_all"
_EncodingDetails = namedtuple("EncodingDetails", _fields)

class EncodingDetails(_EncodingDetails):
    
    CHILD_PROCESS_SCRIPT = ";".join([
        "import sys, os",
        "print(sys.getfilesystemencoding())",
        "print(sys.stdin.encoding + ':' + sys.stdin.errors)",
        "print(sys.stdout.encoding + ':' + sys.stdout.errors)",
        "print(sys.stderr.encoding + ':' + sys.stderr.errors)",
        "print(os.environ.get('LANG', 'not set'))",
        "print(os.environ.get('LC_CTYPE', 'not set'))",
        "print(os.environ.get('LC_ALL', 'not set'))",
    ])

    @classmethod
    def get_expected_details(cls, coercion_expected, fs_encoding, stream_encoding, env_vars):
        
        _stream = stream_encoding + ":{}"
        
        
        stream_info = 2*[_stream.format("surrogateescape")]
        
        stream_info.append(_stream.format("backslashreplace"))
        expected_lang = env_vars.get("LANG", "not set")
        if coercion_expected:
            expected_lc_ctype = CLI_COERCION_TARGET
        else:
            expected_lc_ctype = env_vars.get("LC_CTYPE", "not set")
        expected_lc_all = env_vars.get("LC_ALL", "not set")
        env_info = expected_lang, expected_lc_ctype, expected_lc_all
        return dict(cls(fs_encoding, *stream_info, *env_info)._asdict())

    @classmethod
    def get_child_details(cls, env_vars):
        
        result, py_cmd = run_python_until_end(
            "-X", "utf8=0", "-c", cls.CHILD_PROCESS_SCRIPT,
            **env_vars
        )
        if not result.rc == 0:
            result.fail(py_cmd)
        
        stdout_lines = result.out.decode("ascii").splitlines()
        child_encoding_details = dict(cls(*stdout_lines)._asdict())
        stderr_lines = result.err.decode("ascii").rstrip().splitlines()
        return child_encoding_details, stderr_lines



LEGACY_LOCALE_WARNING = (
    "Python runtime initialized with LC_CTYPE=C (a locale with default ASCII "
    "encoding), which may cause Unicode compatibility problems. Using C.UTF-8, "
    "C.utf8, or UTF-8 (if available) as alternative Unicode-compatible "
    "locales is recommended."
)


CLI_COERCION_WARNING_FMT = (
    "Python detected LC_CTYPE=C: LC_CTYPE coerced to {} (set another locale "
    "or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior)."
)


AVAILABLE_TARGETS = None
CLI_COERCION_TARGET = None
CLI_COERCION_WARNING = None

def setUpModule():
    global AVAILABLE_TARGETS
    global CLI_COERCION_TARGET
    global CLI_COERCION_WARNING

    if AVAILABLE_TARGETS is not None:
        
        return
    AVAILABLE_TARGETS = []

    
    for target_locale in _C_UTF8_LOCALES:
        if _set_locale_in_subprocess(target_locale):
            AVAILABLE_TARGETS.append(target_locale)

    if AVAILABLE_TARGETS:
        
        CLI_COERCION_TARGET = AVAILABLE_TARGETS[0]
        CLI_COERCION_WARNING = CLI_COERCION_WARNING_FMT.format(CLI_COERCION_TARGET)

    if support.verbose:
        print(f"AVAILABLE_TARGETS = {AVAILABLE_TARGETS!r}")
        print(f"EXPECTED_C_LOCALE_EQUIVALENTS = {EXPECTED_C_LOCALE_EQUIVALENTS!r}")
        print(f"EXPECTED_C_LOCALE_STREAM_ENCODING = {EXPECTED_C_LOCALE_STREAM_ENCODING!r}")
        print(f"EXPECTED_C_LOCALE_FS_ENCODING = {EXPECTED_C_LOCALE_FS_ENCODING!r}")
        print(f"EXPECT_COERCION_IN_DEFAULT_LOCALE = {EXPECT_COERCION_IN_DEFAULT_LOCALE!r}")
        print(f"_C_UTF8_LOCALES = {_C_UTF8_LOCALES!r}")
        print(f"_check_nl_langinfo_CODESET = {_check_nl_langinfo_CODESET!r}")


class _LocaleHandlingTestCase(unittest.TestCase):
    

    def _check_child_encoding_details(self,
                                      env_vars,
                                      expected_fs_encoding,
                                      expected_stream_encoding,
                                      expected_warnings,
                                      coercion_expected):
        
        result = EncodingDetails.get_child_details(env_vars)
        encoding_details, stderr_lines = result
        expected_details = EncodingDetails.get_expected_details(
            coercion_expected,
            expected_fs_encoding,
            expected_stream_encoding,
            env_vars
        )
        self.assertEqual(encoding_details, expected_details)
        if expected_warnings is None:
            expected_warnings = []
        self.assertEqual(stderr_lines, expected_warnings)


class LocaleConfigurationTests(_LocaleHandlingTestCase):
    

    @classmethod
    def setUpClass(cls):
        
        
        if not AVAILABLE_TARGETS:
            raise unittest.SkipTest("No C-with-UTF-8 locale available")

    def test_external_target_locale_configuration(self):

        
        
        self.maxDiff = None

        expected_fs_encoding = "utf-8"
        expected_stream_encoding = "utf-8"

        base_var_dict = {
            "LANG": "",
            "LC_CTYPE": "",
            "LC_ALL": "",
            "PYTHONCOERCECLOCALE": "",
        }
        for env_var in ("LANG", "LC_CTYPE"):
            for locale_to_set in AVAILABLE_TARGETS:
                
                
                
                if env_var == "LANG" and locale_to_set == "UTF-8":
                    continue

                with self.subTest(env_var=env_var,
                                  configured_locale=locale_to_set):
                    var_dict = base_var_dict.copy()
                    var_dict[env_var] = locale_to_set
                    self._check_child_encoding_details(var_dict,
                                                       expected_fs_encoding,
                                                       expected_stream_encoding,
                                                       expected_warnings=None,
                                                       coercion_expected=False)



@support.cpython_only
@unittest.skipUnless(sysconfig.get_config_var("PY_COERCE_C_LOCALE"),
                     "C locale coercion disabled at build time")
class LocaleCoercionTests(_LocaleHandlingTestCase):
    

    def _check_c_locale_coercion(self,
                                 fs_encoding, stream_encoding,
                                 coerce_c_locale,
                                 expected_warnings=None,
                                 coercion_expected=True,
                                 **extra_vars):
        
        self.maxDiff = None

        if not AVAILABLE_TARGETS:
            
            fs_encoding = EXPECTED_C_LOCALE_FS_ENCODING
            stream_encoding = EXPECTED_C_LOCALE_STREAM_ENCODING
            coercion_expected = False
            if expected_warnings:
                expected_warnings = [LEGACY_LOCALE_WARNING]

        base_var_dict = {
            "LANG": "",
            "LC_CTYPE": "",
            "LC_ALL": "",
            "PYTHONCOERCECLOCALE": "",
        }
        base_var_dict.update(extra_vars)
        if coerce_c_locale is not None:
            base_var_dict["PYTHONCOERCECLOCALE"] = coerce_c_locale

        
        with self.subTest(default_locale=True,
                          PYTHONCOERCECLOCALE=coerce_c_locale):
            if EXPECT_COERCION_IN_DEFAULT_LOCALE:
                _expected_warnings = expected_warnings
                _coercion_expected = coercion_expected
            else:
                _expected_warnings = None
                _coercion_expected = False
            
            
            
            
            if (support.is_android and
                    _expected_warnings == [CLI_COERCION_WARNING]):
                _expected_warnings = None
            self._check_child_encoding_details(base_var_dict,
                                               fs_encoding,
                                               stream_encoding,
                                               _expected_warnings,
                                               _coercion_expected)

        
        for locale_to_set in EXPECTED_C_LOCALE_EQUIVALENTS:
            for env_var in ("LANG", "LC_CTYPE"):
                with self.subTest(env_var=env_var,
                                  nominal_locale=locale_to_set,
                                  PYTHONCOERCECLOCALE=coerce_c_locale):
                    var_dict = base_var_dict.copy()
                    var_dict[env_var] = locale_to_set
                    
                    self._check_child_encoding_details(var_dict,
                                                       fs_encoding,
                                                       stream_encoding,
                                                       expected_warnings,
                                                       coercion_expected)

    def test_PYTHONCOERCECLOCALE_not_set(self):
        
        self._check_c_locale_coercion("utf-8", "utf-8", coerce_c_locale=None)

    def test_PYTHONCOERCECLOCALE_not_zero(self):
        
        
        for setting in ("", "1", "true", "false"):
            self._check_c_locale_coercion("utf-8", "utf-8", coerce_c_locale=setting)

    def test_PYTHONCOERCECLOCALE_set_to_warn(self):
        
        self._check_c_locale_coercion("utf-8", "utf-8",
                                      coerce_c_locale="warn",
                                      expected_warnings=[CLI_COERCION_WARNING])


    def test_PYTHONCOERCECLOCALE_set_to_zero(self):
        
        self._check_c_locale_coercion(EXPECTED_C_LOCALE_FS_ENCODING,
                                      EXPECTED_C_LOCALE_STREAM_ENCODING,
                                      coerce_c_locale="0",
                                      coercion_expected=False)
        
        self._check_c_locale_coercion(EXPECTED_C_LOCALE_FS_ENCODING,
                                      EXPECTED_C_LOCALE_STREAM_ENCODING,
                                      coerce_c_locale="0",
                                      LC_ALL="C",
                                      coercion_expected=False)

    def test_LC_ALL_set_to_C(self):
        
        self._check_c_locale_coercion(EXPECTED_C_LOCALE_FS_ENCODING,
                                      EXPECTED_C_LOCALE_STREAM_ENCODING,
                                      coerce_c_locale=None,
                                      LC_ALL="C",
                                      coercion_expected=False)
        
        self._check_c_locale_coercion(EXPECTED_C_LOCALE_FS_ENCODING,
                                      EXPECTED_C_LOCALE_STREAM_ENCODING,
                                      coerce_c_locale="warn",
                                      LC_ALL="C",
                                      expected_warnings=[LEGACY_LOCALE_WARNING],
                                      coercion_expected=False)

    def test_PYTHONCOERCECLOCALE_set_to_one(self):
        
        old_loc = locale.setlocale(locale.LC_CTYPE, None)
        self.addCleanup(locale.setlocale, locale.LC_CTYPE, old_loc)
        try:
            loc = locale.setlocale(locale.LC_CTYPE, "")
        except locale.Error as e:
            self.skipTest(str(e))
        if loc == "C":
            self.skipTest("test requires LC_CTYPE locale different than C")
        if loc in TARGET_LOCALES :
            self.skipTest("coerced LC_CTYPE locale: %s" % loc)

        
        
        code = 'import locale; print(locale.setlocale(locale.LC_CTYPE, None))'
        env = dict(os.environ, PYTHONCOERCECLOCALE='1')
        cmd = subprocess.run([sys.executable, '-c', code],
                             stdout=subprocess.PIPE,
                             env=env,
                             text=True)
        self.assertEqual(cmd.stdout.rstrip(), loc)


def tearDownModule():
    support.reap_children()


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