1616
1717# Set our expectation for the default encoding used in the C locale
1818# for the filesystem encoding and the standard streams
19+ C_LOCALE_STREAM_ENCODING = "ascii"
1920if sys .platform == "darwin" :
20- EXPECTED_C_LOCALE_FSENCODING = "utf-8"
21+ C_LOCALE_FS_ENCODING = "utf-8"
2122else :
22- EXPECTED_C_LOCALE_FSENCODING = "ascii"
23+ C_LOCALE_FS_ENCODING = C_LOCALE_STREAM_ENCODING
2324
2425# XXX (ncoghlan): The above is probably still wrong for:
2526# * Windows when PYTHONLEGACYWINDOWSFSENCODING is set
@@ -52,15 +53,15 @@ class EncodingDetails(_EncodingDetails):
5253 ])
5354
5455 @classmethod
55- def get_expected_details (cls , expected_fsencoding ):
56+ def get_expected_details (cls , fs_encoding , stream_encoding ):
5657 """Returns expected child process details for a given encoding"""
57- _stream = expected_fsencoding + ":{}"
58+ _stream = stream_encoding + ":{}"
5859 # stdin and stdout should use surrogateescape either because the
5960 # coercion triggered, or because the C locale was detected
6061 stream_info = 2 * [_stream .format ("surrogateescape" )]
6162 # stderr should always use backslashreplace
6263 stream_info .append (_stream .format ("backslashreplace" ))
63- return dict (cls (expected_fsencoding , * stream_info )._asdict ())
64+ return dict (cls (fs_encoding , * stream_info )._asdict ())
6465
6566 @staticmethod
6667 def _handle_output_variations (data ):
@@ -107,21 +108,22 @@ class _ChildProcessEncodingTestCase(unittest.TestCase):
107108
108109 def _check_child_encoding_details (self ,
109110 env_vars ,
110- expected_fsencoding ,
111+ expected_fs_encoding ,
112+ expected_stream_encoding ,
111113 expected_warning ):
112114 """Check the C locale handling for the given process environment
113115
114116 Parameters:
115- expected_fsencoding: the encoding the child is expected to report
116- allow_c_locale: setting to use for PYTHONALLOWCLOCALE
117- None: don't set the variable at all
118- str: the value set in the child's environment
117+ expected_fs_encoding: expected sys.getfilesystemencoding() result
118+ expected_stream_encoding: expected encoding for standard streams
119+ expected_warning: stderr output to expect (if any)
119120 """
120121 result = EncodingDetails .get_child_details (env_vars )
121122 encoding_details , stderr_lines = result
122123 self .assertEqual (encoding_details ,
123124 EncodingDetails .get_expected_details (
124- expected_fsencoding ))
125+ expected_fs_encoding ,
126+ expected_stream_encoding ))
125127 self .assertEqual (stderr_lines , expected_warning )
126128
127129# Details of the shared library warning emitted at runtime
@@ -140,12 +142,17 @@ class LocaleWarningTests(_ChildProcessEncodingTestCase):
140142 def test_library_c_locale_warning (self ):
141143 self .maxDiff = None
142144 for locale_to_set in ("C" , "POSIX" , "invalid.ascii" ):
145+ # XXX (ncoghlan): Mac OS X doesn't behave as expected in the
146+ # POSIX locale, so we skip that for now
147+ if sys .platform == "darwin" and locale_to_set == "POSIX" :
148+ continue
143149 var_dict = {
144150 "LC_ALL" : locale_to_set
145151 }
146152 with self .subTest (forced_locale = locale_to_set ):
147153 self ._check_child_encoding_details (var_dict ,
148- EXPECTED_C_LOCALE_FSENCODING ,
154+ C_LOCALE_FS_ENCODING ,
155+ C_LOCALE_STREAM_ENCODING ,
149156 [LIBRARY_C_LOCALE_WARNING ])
150157
151158# Details of the CLI locale coercion warning emitted at runtime
@@ -190,7 +197,8 @@ def test_external_target_locale_configuration(self):
190197 self .maxDiff = None
191198
192199 expected_warning = []
193- expected_fsencoding = "utf-8"
200+ expected_fs_encoding = "utf-8"
201+ expected_stream_encoding = "utf-8"
194202
195203 base_var_dict = {
196204 "LANG" : "" ,
@@ -209,7 +217,8 @@ def test_external_target_locale_configuration(self):
209217 var_dict = base_var_dict .copy ()
210218 var_dict [env_var ] = locale_to_set
211219 self ._check_child_encoding_details (var_dict ,
212- expected_fsencoding ,
220+ expected_fs_encoding ,
221+ expected_stream_encoding ,
213222 expected_warning )
214223
215224
@@ -220,12 +229,13 @@ def test_external_target_locale_configuration(self):
220229class LocaleCoercionTests (_LocaleCoercionTargetsTestCase ):
221230 # Test implicit reconfiguration of the environment during CLI startup
222231
223- def _check_c_locale_coercion (self , expected_fsencoding , coerce_c_locale ):
232+ def _check_c_locale_coercion (self , fs_encoding , stream_encoding , coerce_c_locale ):
224233 """Check the C locale handling for various configurations
225234
226235 Parameters:
227- expected_fsencoding: the encoding the child is expected to report
228- allow_c_locale: setting to use for PYTHONALLOWCLOCALE
236+ fs_encoding: expected sys.getfilesystemencoding() result
237+ stream_encoding: expected encoding for standard streams
238+ coerce_c_locale: setting to use for PYTHONCOERCECLOCALE
229239 None: don't set the variable at all
230240 str: the value set in the child's environment
231241 """
@@ -246,6 +256,10 @@ def _check_c_locale_coercion(self, expected_fsencoding, coerce_c_locale):
246256 }
247257 for env_var in ("LANG" , "LC_CTYPE" ):
248258 for locale_to_set in ("" , "C" , "POSIX" , "invalid.ascii" ):
259+ # XXX (ncoghlan): Mac OS X doesn't behave as expected in the
260+ # POSIX locale, so we skip that for now
261+ if sys .platform == "darwin" and locale_to_set == "POSIX" :
262+ continue
249263 with self .subTest (env_var = env_var ,
250264 nominal_locale = locale_to_set ,
251265 PYTHONCOERCECLOCALE = coerce_c_locale ):
@@ -254,22 +268,24 @@ def _check_c_locale_coercion(self, expected_fsencoding, coerce_c_locale):
254268 if coerce_c_locale is not None :
255269 var_dict ["PYTHONCOERCECLOCALE" ] = coerce_c_locale
256270 self ._check_child_encoding_details (var_dict ,
257- expected_fsencoding ,
271+ fs_encoding ,
272+ stream_encoding ,
258273 expected_warning )
259274
260275 def test_test_PYTHONCOERCECLOCALE_not_set (self ):
261276 # This should coerce to the first available target locale by default
262- self ._check_c_locale_coercion ("utf-8" , coerce_c_locale = None )
277+ self ._check_c_locale_coercion ("utf-8" , "utf-8" , coerce_c_locale = None )
263278
264279 def test_PYTHONCOERCECLOCALE_not_zero (self ):
265280 # *Any* string other that "0" is considered "set" for our purposes
266281 # and hence should result in the locale coercion being enabled
267282 for setting in ("" , "1" , "true" , "false" ):
268- self ._check_c_locale_coercion ("utf-8" , coerce_c_locale = setting )
283+ self ._check_c_locale_coercion ("utf-8" , "utf-8" , coerce_c_locale = setting )
269284
270285 def test_PYTHONCOERCECLOCALE_set_to_zero (self ):
271286 # The setting "0" should result in the locale coercion being disabled
272- self ._check_c_locale_coercion (EXPECTED_C_LOCALE_FSENCODING ,
287+ self ._check_c_locale_coercion (C_LOCALE_FS_ENCODING ,
288+ C_LOCALE_STREAM_ENCODING ,
273289 coerce_c_locale = "0" )
274290
275291
0 commit comments