@@ -293,6 +293,21 @@ def test_utf8_bom_and_utf8_coding_line(self):
293293 b'print(ascii("\xc3 \xa4 "))\n ' )
294294 self .check_script_output (src , br"'\xe4'" )
295295
296+ def test_utf8_bom_and_non_utf8_first_coding_line (self ):
297+ src = (b'\xef \xbb \xbf #coding:iso-8859-15\n '
298+ b'raise RuntimeError\n ' )
299+ self .check_script_error (src ,
300+ br"encoding problem: iso-8859-15 with BOM" ,
301+ lineno = 1 )
302+
303+ def test_utf8_bom_and_non_utf8_second_coding_line (self ):
304+ src = (b'\xef \xbb \xbf #first\n '
305+ b'#coding:iso-8859-15\n '
306+ b'raise RuntimeError\n ' )
307+ self .check_script_error (src ,
308+ br"encoding problem: iso-8859-15 with BOM" ,
309+ lineno = 2 )
310+
296311 def test_non_utf8_shebang (self ):
297312 src = (b'#!/home/\xa4 /bin/python\n '
298313 b'#coding:iso-8859-15\n '
@@ -308,45 +323,50 @@ def test_utf8_shebang_error(self):
308323 def test_non_utf8_shebang_error (self ):
309324 src = (b'#!/home/\xa4 /bin/python\n '
310325 b'raise RuntimeError\n ' )
311- self .check_script_error (src , br"Non-UTF-8 code starting with .* on line 1" )
326+ self .check_script_error (src , br"Non-UTF-8 code starting with .* on line 1" ,
327+ lineno = 1 )
312328
313329 def test_non_utf8_second_line_error (self ):
314- src = (b'#\n '
315- b'#\xa4 \n '
330+ src = (b'#first \n '
331+ b'#second \xa4 \n '
316332 b'raise RuntimeError\n ' )
317333 self .check_script_error (src ,
318- br"Non-UTF-8 code starting with .* on line 2" )
334+ br"Non-UTF-8 code starting with .* on line 2" ,
335+ lineno = 2 )
319336
320337 def test_non_utf8_third_line_error (self ):
321- src = (b'#\n '
322- b'#\n '
323- b'#\xa4 \n '
338+ src = (b'#first \n '
339+ b'#second \n '
340+ b'#third \xa4 \n '
324341 b'raise RuntimeError\n ' )
325342 self .check_script_error (src ,
326- br"Non-UTF-8 code starting with .* on line 3" )
343+ br"Non-UTF-8 code starting with .* on line 3" ,
344+ lineno = 3 )
327345
328346 def test_utf8_bom_non_utf8_third_line_error (self ):
329- src = (b'\xef \xbb \xbf #\n '
330- b'#\n '
331- b'#\xa4 \n '
347+ src = (b'\xef \xbb \xbf #first \n '
348+ b'#second \n '
349+ b'#third \xa4 \n '
332350 b'raise RuntimeError\n ' )
333351 self .check_script_error (src ,
334352 br"Non-UTF-8 code starting with .* on line 3|"
335- br"'utf-8' codec can't decode byte" )
353+ br"'utf-8' codec can't decode byte" ,
354+ lineno = 3 )
336355
337356 def test_utf_8_non_utf8_third_line_error (self ):
338357 src = (b'#coding: utf-8\n '
339- b'#\n '
340- b'#\xa4 \n '
358+ b'#second \n '
359+ b'#third \xa4 \n '
341360 b'raise RuntimeError\n ' )
342361 self .check_script_error (src ,
343362 br"Non-UTF-8 code starting with .* on line 3|"
344- br"'utf-8' codec can't decode byte" )
363+ br"'utf-8' codec can't decode byte" ,
364+ lineno = 3 )
345365
346366 def test_utf8_non_utf8_third_line_error (self ):
347367 src = (b'#coding: utf8\n '
348- b'#\n '
349- b'#\xa4 \n '
368+ b'#second \n '
369+ b'#third \xa4 \n '
350370 b'raise RuntimeError\n ' )
351371 self .check_script_error (src ,
352372 br"'utf-8' codec can't decode byte|"
@@ -461,9 +481,17 @@ def check_script_output(self, src, expected):
461481 out = stdout .getvalue ().encode ('latin1' )
462482 self .assertEqual (out .rstrip (), expected )
463483
464- def check_script_error (self , src , expected ):
465- with self .assertRaisesRegex (SyntaxError , expected . decode () ) as cm :
484+ def check_script_error (self , src , expected , lineno = ... ):
485+ with self .assertRaises (SyntaxError ) as cm :
466486 exec (src )
487+ exc = cm .exception
488+ self .assertRegex (str (exc ), expected .decode ())
489+ if lineno is not ...:
490+ self .assertEqual (exc .lineno , lineno )
491+ line = src .splitlines ()[lineno - 1 ].decode (errors = 'replace' )
492+ if lineno == 1 :
493+ line = line .removeprefix ('\ufeff ' )
494+ self .assertEqual (line , exc .text )
467495
468496
469497class FileSourceEncodingTest (AbstractSourceEncodingTest , unittest .TestCase ):
@@ -476,13 +504,21 @@ def check_script_output(self, src, expected):
476504 res = script_helper .assert_python_ok (fn )
477505 self .assertEqual (res .out .rstrip (), expected )
478506
479- def check_script_error (self , src , expected ):
507+ def check_script_error (self , src , expected , lineno = ... ):
480508 with tempfile .TemporaryDirectory () as tmpd :
481509 fn = os .path .join (tmpd , 'test.py' )
482510 with open (fn , 'wb' ) as fp :
483511 fp .write (src )
484512 res = script_helper .assert_python_failure (fn )
485- self .assertRegex (res .err .rstrip ().splitlines ()[- 1 ], b'SyntaxError.*?' + expected )
513+ err = res .err .rstrip ()
514+ self .assertRegex (err .splitlines ()[- 1 ], b'SyntaxError.*?' + expected )
515+ if lineno is not ...:
516+ self .assertIn (f', line { lineno } \n ' .encode (), err )
517+ line = src .splitlines ()[lineno - 1 ].decode (errors = 'replace' )
518+ if lineno == 1 :
519+ line = line .removeprefix ('\ufeff ' )
520+ self .assertIn (line .encode (), err )
521+
486522
487523
488524if __name__ == "__main__" :
0 commit comments