diff options
author | Eric Smith <eric@trueblade.com> | 2008-03-18 23:45:49 (GMT) |
---|---|---|
committer | Eric Smith <eric@trueblade.com> | 2008-03-18 23:45:49 (GMT) |
commit | 7c47894a2aaa8dbc5397a256b16cd7deddef1d7e (patch) | |
tree | 8a04cef2a98907c1f20cde46f0efec77a5730a65 /Lib | |
parent | 6c0ff8aacd5b493892878e138b97af66e4bfaf37 (diff) | |
download | cpython-7c47894a2aaa8dbc5397a256b16cd7deddef1d7e.zip cpython-7c47894a2aaa8dbc5397a256b16cd7deddef1d7e.tar.gz cpython-7c47894a2aaa8dbc5397a256b16cd7deddef1d7e.tar.bz2 |
Backport of the print function, using a __future__ import.
This work is substantially Anthony Baxter's, from issue
1633807. I just freshened it, made a few minor tweaks,
and added the test cases. I also created issue 2412,
which is to check for 2to3's behavior with the print
function. I also added myself to ACKS.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/__future__.py | 6 | ||||
-rw-r--r-- | Lib/test/test_print.py | 129 |
2 files changed, 135 insertions, 0 deletions
diff --git a/Lib/__future__.py b/Lib/__future__.py index d8e14d1..ea14bf3 100644 --- a/Lib/__future__.py +++ b/Lib/__future__.py @@ -53,6 +53,7 @@ all_feature_names = [ "division", "absolute_import", "with_statement", + "print_function", ] __all__ = ["all_feature_names"] + all_feature_names @@ -66,6 +67,7 @@ CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000) CO_FUTURE_DIVISION = 0x2000 # division CO_FUTURE_ABSOLUTE_IMPORT = 0x4000 # perform absolute imports by default CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement +CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function class _Feature: def __init__(self, optionalRelease, mandatoryRelease, compiler_flag): @@ -114,3 +116,7 @@ absolute_import = _Feature((2, 5, 0, "alpha", 1), with_statement = _Feature((2, 5, 0, "alpha", 1), (2, 6, 0, "alpha", 0), CO_FUTURE_WITH_STATEMENT) + +print_function = _Feature((2, 6, 0, "alpha", 2), + (3, 0, 0, "alpha", 0), + CO_FUTURE_PRINT_FUNCTION) diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py new file mode 100644 index 0000000..db09c9c --- /dev/null +++ b/Lib/test/test_print.py @@ -0,0 +1,129 @@ +"""Test correct operation of the print function. +""" + +from __future__ import print_function + +import unittest +from test import test_support + +import sys +try: + # 3.x + from io import StringIO +except ImportError: + # 2.x + from StringIO import StringIO + +from contextlib import contextmanager + +NotDefined = object() + +# A dispatch table all 8 combinations of providing +# sep, end, and file +# I use this machinery so that I'm not just passing default +# values to print, I'm eiher passing or not passing in the +# arguments +dispatch = { + (False, False, False): + lambda args, sep, end, file: print(*args), + (False, False, True): + lambda args, sep, end, file: print(file=file, *args), + (False, True, False): + lambda args, sep, end, file: print(end=end, *args), + (False, True, True): + lambda args, sep, end, file: print(end=end, file=file, *args), + (True, False, False): + lambda args, sep, end, file: print(sep=sep, *args), + (True, False, True): + lambda args, sep, end, file: print(sep=sep, file=file, *args), + (True, True, False): + lambda args, sep, end, file: print(sep=sep, end=end, *args), + (True, True, True): + lambda args, sep, end, file: print(sep=sep, end=end, file=file, *args), + } + +@contextmanager +def stdout_redirected(new_stdout): + save_stdout = sys.stdout + sys.stdout = new_stdout + try: + yield None + finally: + sys.stdout = save_stdout + +# Class used to test __str__ and print +class ClassWith__str__: + def __init__(self, x): + self.x = x + def __str__(self): + return self.x + +class TestPrint(unittest.TestCase): + def check(self, expected, args, + sep=NotDefined, end=NotDefined, file=NotDefined): + # Capture sys.stdout in a StringIO. Call print with args, + # and with sep, end, and file, if they're defined. Result + # must match expected. + + # Look up the actual function to call, based on if sep, end, and file + # are defined + fn = dispatch[(sep is not NotDefined, + end is not NotDefined, + file is not NotDefined)] + + t = StringIO() + with stdout_redirected(t): + fn(args, sep, end, file) + + self.assertEqual(t.getvalue(), expected) + + def test_print(self): + def x(expected, args, sep=NotDefined, end=NotDefined): + # Run the test 2 ways: not using file, and using + # file directed to a StringIO + + self.check(expected, args, sep=sep, end=end) + + # When writing to a file, stdout is expected to be empty + o = StringIO() + self.check('', args, sep=sep, end=end, file=o) + + # And o will contain the expected output + self.assertEqual(o.getvalue(), expected) + + x('\n', ()) + x('a\n', ('a',)) + x('None\n', (None,)) + x('1 2\n', (1, 2)) + x('1 2\n', (1, ' ', 2)) + x('1*2\n', (1, 2), sep='*') + x('1 s', (1, 's'), end='') + x('a\nb\n', ('a', 'b'), sep='\n') + x('1.01', (1.0, 1), sep='', end='') + x('1*a*1.3+', (1, 'a', 1.3), sep='*', end='+') + x('a\n\nb\n', ('a\n', 'b'), sep='\n') + x('\0+ +\0\n', ('\0', ' ', '\0'), sep='+') + + x('a\n b\n', ('a\n', 'b')) + x('a\n b\n', ('a\n', 'b'), sep=None) + x('a\n b\n', ('a\n', 'b'), end=None) + x('a\n b\n', ('a\n', 'b'), sep=None, end=None) + + x('*\n', (ClassWith__str__('*'),)) + x('abc 1\n', (ClassWith__str__('abc'), 1)) + + # 2.x unicode tests + x(u'1 2\n', ('1', u'2')) + x(u'u\1234\n', (u'u\1234',)) + x(u' abc 1\n', (' ', ClassWith__str__(u'abc'), 1)) + + # errors + self.assertRaises(TypeError, print, '', sep=3) + self.assertRaises(TypeError, print, '', end=3) + self.assertRaises(AttributeError, print, '', file='') + +def test_main(): + test_support.run_unittest(TestPrint) + +if __name__ == "__main__": + test_main() |