17db96d56Sopenharmony_ciimport unittest 27db96d56Sopenharmony_ciimport sys 37db96d56Sopenharmony_cifrom io import StringIO 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_cifrom test import support 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciNotDefined = object() 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci# A dispatch table all 8 combinations of providing 107db96d56Sopenharmony_ci# sep, end, and file. 117db96d56Sopenharmony_ci# I use this machinery so that I'm not just passing default 127db96d56Sopenharmony_ci# values to print, I'm either passing or not passing in the 137db96d56Sopenharmony_ci# arguments. 147db96d56Sopenharmony_cidispatch = { 157db96d56Sopenharmony_ci (False, False, False): 167db96d56Sopenharmony_ci lambda args, sep, end, file: print(*args), 177db96d56Sopenharmony_ci (False, False, True): 187db96d56Sopenharmony_ci lambda args, sep, end, file: print(file=file, *args), 197db96d56Sopenharmony_ci (False, True, False): 207db96d56Sopenharmony_ci lambda args, sep, end, file: print(end=end, *args), 217db96d56Sopenharmony_ci (False, True, True): 227db96d56Sopenharmony_ci lambda args, sep, end, file: print(end=end, file=file, *args), 237db96d56Sopenharmony_ci (True, False, False): 247db96d56Sopenharmony_ci lambda args, sep, end, file: print(sep=sep, *args), 257db96d56Sopenharmony_ci (True, False, True): 267db96d56Sopenharmony_ci lambda args, sep, end, file: print(sep=sep, file=file, *args), 277db96d56Sopenharmony_ci (True, True, False): 287db96d56Sopenharmony_ci lambda args, sep, end, file: print(sep=sep, end=end, *args), 297db96d56Sopenharmony_ci (True, True, True): 307db96d56Sopenharmony_ci lambda args, sep, end, file: print(sep=sep, end=end, file=file, *args), 317db96d56Sopenharmony_ci} 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci# Class used to test __str__ and print 357db96d56Sopenharmony_ciclass ClassWith__str__: 367db96d56Sopenharmony_ci def __init__(self, x): 377db96d56Sopenharmony_ci self.x = x 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci def __str__(self): 407db96d56Sopenharmony_ci return self.x 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ciclass TestPrint(unittest.TestCase): 447db96d56Sopenharmony_ci """Test correct operation of the print function.""" 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci def check(self, expected, args, 477db96d56Sopenharmony_ci sep=NotDefined, end=NotDefined, file=NotDefined): 487db96d56Sopenharmony_ci # Capture sys.stdout in a StringIO. Call print with args, 497db96d56Sopenharmony_ci # and with sep, end, and file, if they're defined. Result 507db96d56Sopenharmony_ci # must match expected. 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci # Look up the actual function to call, based on if sep, end, 537db96d56Sopenharmony_ci # and file are defined. 547db96d56Sopenharmony_ci fn = dispatch[(sep is not NotDefined, 557db96d56Sopenharmony_ci end is not NotDefined, 567db96d56Sopenharmony_ci file is not NotDefined)] 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci with support.captured_stdout() as t: 597db96d56Sopenharmony_ci fn(args, sep, end, file) 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci self.assertEqual(t.getvalue(), expected) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci def test_print(self): 647db96d56Sopenharmony_ci def x(expected, args, sep=NotDefined, end=NotDefined): 657db96d56Sopenharmony_ci # Run the test 2 ways: not using file, and using 667db96d56Sopenharmony_ci # file directed to a StringIO. 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_ci self.check(expected, args, sep=sep, end=end) 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci # When writing to a file, stdout is expected to be empty 717db96d56Sopenharmony_ci o = StringIO() 727db96d56Sopenharmony_ci self.check('', args, sep=sep, end=end, file=o) 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci # And o will contain the expected output 757db96d56Sopenharmony_ci self.assertEqual(o.getvalue(), expected) 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci x('\n', ()) 787db96d56Sopenharmony_ci x('a\n', ('a',)) 797db96d56Sopenharmony_ci x('None\n', (None,)) 807db96d56Sopenharmony_ci x('1 2\n', (1, 2)) 817db96d56Sopenharmony_ci x('1 2\n', (1, ' ', 2)) 827db96d56Sopenharmony_ci x('1*2\n', (1, 2), sep='*') 837db96d56Sopenharmony_ci x('1 s', (1, 's'), end='') 847db96d56Sopenharmony_ci x('a\nb\n', ('a', 'b'), sep='\n') 857db96d56Sopenharmony_ci x('1.01', (1.0, 1), sep='', end='') 867db96d56Sopenharmony_ci x('1*a*1.3+', (1, 'a', 1.3), sep='*', end='+') 877db96d56Sopenharmony_ci x('a\n\nb\n', ('a\n', 'b'), sep='\n') 887db96d56Sopenharmony_ci x('\0+ +\0\n', ('\0', ' ', '\0'), sep='+') 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci x('a\n b\n', ('a\n', 'b')) 917db96d56Sopenharmony_ci x('a\n b\n', ('a\n', 'b'), sep=None) 927db96d56Sopenharmony_ci x('a\n b\n', ('a\n', 'b'), end=None) 937db96d56Sopenharmony_ci x('a\n b\n', ('a\n', 'b'), sep=None, end=None) 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci x('*\n', (ClassWith__str__('*'),)) 967db96d56Sopenharmony_ci x('abc 1\n', (ClassWith__str__('abc'), 1)) 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci # errors 997db96d56Sopenharmony_ci self.assertRaises(TypeError, print, '', sep=3) 1007db96d56Sopenharmony_ci self.assertRaises(TypeError, print, '', end=3) 1017db96d56Sopenharmony_ci self.assertRaises(AttributeError, print, '', file='') 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci def test_print_flush(self): 1047db96d56Sopenharmony_ci # operation of the flush flag 1057db96d56Sopenharmony_ci class filelike: 1067db96d56Sopenharmony_ci def __init__(self): 1077db96d56Sopenharmony_ci self.written = '' 1087db96d56Sopenharmony_ci self.flushed = 0 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_ci def write(self, str): 1117db96d56Sopenharmony_ci self.written += str 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci def flush(self): 1147db96d56Sopenharmony_ci self.flushed += 1 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci f = filelike() 1177db96d56Sopenharmony_ci print(1, file=f, end='', flush=True) 1187db96d56Sopenharmony_ci print(2, file=f, end='', flush=True) 1197db96d56Sopenharmony_ci print(3, file=f, flush=False) 1207db96d56Sopenharmony_ci self.assertEqual(f.written, '123\n') 1217db96d56Sopenharmony_ci self.assertEqual(f.flushed, 2) 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci # ensure exceptions from flush are passed through 1247db96d56Sopenharmony_ci class noflush: 1257db96d56Sopenharmony_ci def write(self, str): 1267db96d56Sopenharmony_ci pass 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci def flush(self): 1297db96d56Sopenharmony_ci raise RuntimeError 1307db96d56Sopenharmony_ci self.assertRaises(RuntimeError, print, 1, file=noflush(), flush=True) 1317db96d56Sopenharmony_ci 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ciclass TestPy2MigrationHint(unittest.TestCase): 1347db96d56Sopenharmony_ci """Test that correct hint is produced analogous to Python3 syntax, 1357db96d56Sopenharmony_ci if print statement is executed as in Python 2. 1367db96d56Sopenharmony_ci """ 1377db96d56Sopenharmony_ci 1387db96d56Sopenharmony_ci def test_normal_string(self): 1397db96d56Sopenharmony_ci python2_print_str = 'print "Hello World"' 1407db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as context: 1417db96d56Sopenharmony_ci exec(python2_print_str) 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", 1447db96d56Sopenharmony_ci str(context.exception)) 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci def test_string_with_soft_space(self): 1477db96d56Sopenharmony_ci python2_print_str = 'print "Hello World",' 1487db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as context: 1497db96d56Sopenharmony_ci exec(python2_print_str) 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ci self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", 1527db96d56Sopenharmony_ci str(context.exception)) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci def test_string_with_excessive_whitespace(self): 1557db96d56Sopenharmony_ci python2_print_str = 'print "Hello World", ' 1567db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as context: 1577db96d56Sopenharmony_ci exec(python2_print_str) 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ci self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", 1607db96d56Sopenharmony_ci str(context.exception)) 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci def test_string_with_leading_whitespace(self): 1637db96d56Sopenharmony_ci python2_print_str = '''if 1: 1647db96d56Sopenharmony_ci print "Hello World" 1657db96d56Sopenharmony_ci ''' 1667db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as context: 1677db96d56Sopenharmony_ci exec(python2_print_str) 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", 1707db96d56Sopenharmony_ci str(context.exception)) 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci # bpo-32685: Suggestions for print statement should be proper when 1737db96d56Sopenharmony_ci # it is in the same line as the header of a compound statement 1747db96d56Sopenharmony_ci # and/or followed by a semicolon 1757db96d56Sopenharmony_ci def test_string_with_semicolon(self): 1767db96d56Sopenharmony_ci python2_print_str = 'print p;' 1777db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as context: 1787db96d56Sopenharmony_ci exec(python2_print_str) 1797db96d56Sopenharmony_ci 1807db96d56Sopenharmony_ci self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", 1817db96d56Sopenharmony_ci str(context.exception)) 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci def test_string_in_loop_on_same_line(self): 1847db96d56Sopenharmony_ci python2_print_str = 'for i in s: print i' 1857db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as context: 1867db96d56Sopenharmony_ci exec(python2_print_str) 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci self.assertIn("Missing parentheses in call to 'print'. Did you mean print(...)", 1897db96d56Sopenharmony_ci str(context.exception)) 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_ci def test_stream_redirection_hint_for_py2_migration(self): 1927db96d56Sopenharmony_ci # Test correct hint produced for Py2 redirection syntax 1937db96d56Sopenharmony_ci with self.assertRaises(TypeError) as context: 1947db96d56Sopenharmony_ci print >> sys.stderr, "message" 1957db96d56Sopenharmony_ci self.assertIn('Did you mean "print(<message>, ' 1967db96d56Sopenharmony_ci 'file=<output_stream>)"?', str(context.exception)) 1977db96d56Sopenharmony_ci 1987db96d56Sopenharmony_ci # Test correct hint is produced in the case where RHS implements 1997db96d56Sopenharmony_ci # __rrshift__ but returns NotImplemented 2007db96d56Sopenharmony_ci with self.assertRaises(TypeError) as context: 2017db96d56Sopenharmony_ci print >> 42 2027db96d56Sopenharmony_ci self.assertIn('Did you mean "print(<message>, ' 2037db96d56Sopenharmony_ci 'file=<output_stream>)"?', str(context.exception)) 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci # Test stream redirection hint is specific to print 2067db96d56Sopenharmony_ci with self.assertRaises(TypeError) as context: 2077db96d56Sopenharmony_ci max >> sys.stderr 2087db96d56Sopenharmony_ci self.assertNotIn('Did you mean ', str(context.exception)) 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci # Test stream redirection hint is specific to rshift 2117db96d56Sopenharmony_ci with self.assertRaises(TypeError) as context: 2127db96d56Sopenharmony_ci print << sys.stderr 2137db96d56Sopenharmony_ci self.assertNotIn('Did you mean', str(context.exception)) 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci # Ensure right operand implementing rrshift still works 2167db96d56Sopenharmony_ci class OverrideRRShift: 2177db96d56Sopenharmony_ci def __rrshift__(self, lhs): 2187db96d56Sopenharmony_ci return 42 # Force result independent of LHS 2197db96d56Sopenharmony_ci 2207db96d56Sopenharmony_ci self.assertEqual(print >> OverrideRRShift(), 42) 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci 2247db96d56Sopenharmony_ciif __name__ == "__main__": 2257db96d56Sopenharmony_ci unittest.main() 226