GeezerVison is showing github.com — Backport of the print function, using a __future__ import. · yahalit/python@cfd81f9
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: Include/code.h +2-1Lines changed: 2 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -48,11 +48,12 @@ typedef struct { | 48 | 48 | #define CO_FUTURE_DIVISION 0x2000 | 49 | 49 | #define CO_FUTURE_ABSOLUTE_IMPORT 0x4000 /* do absolute imports by default */ | 50 | 50 | #define CO_FUTURE_WITH_STATEMENT 0x8000 | | 51 | +#define CO_FUTURE_PRINT_FUNCTION 0x10000 | 51 | 52 |
| 52 | 53 | /* This should be defined if a future statement modifies the syntax. | 53 | 54 | For example, when a keyword is added. | 54 | 55 | */ | 55 | | -#if 0 | | 56 | +#if 1 | 56 | 57 | #define PY_PARSER_REQUIRES_FUTURE_KEYWORD | 57 | 58 | #endif | 58 | 59 |
| |
Collapse file Copy file name to clipboardExpand all lines: Include/compile.h +2Lines changed: 2 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -24,6 +24,8 @@ typedef struct { | 24 | 24 | #define FUTURE_DIVISION "division" | 25 | 25 | #define FUTURE_ABSOLUTE_IMPORT "absolute_import" | 26 | 26 | #define FUTURE_WITH_STATEMENT "with_statement" | | 27 | +#define FUTURE_PRINT_FUNCTION "print_function" | | 28 | + | 27 | 29 |
| 28 | 30 | struct _mod; /* Declare the existence of this type */ | 29 | 31 | PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *, | |
Collapse file Copy file name to clipboardExpand all lines: Include/parsetok.h +4Lines changed: 4 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -27,6 +27,10 @@ typedef struct { | 27 | 27 | #define PyPARSE_WITH_IS_KEYWORD 0x0003 | 28 | 28 | #endif | 29 | 29 |
| | 30 | +#define PyPARSE_PRINT_IS_FUNCTION 0x0004 | | 31 | + | | 32 | + | | 33 | + | 30 | 34 | PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, | 31 | 35 | perrdetail *); | 32 | 36 | PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int, | |
Collapse file Copy file name to clipboardExpand all lines: Include/pythonrun.h +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -8,7 +8,7 @@ extern "C" { | 8 | 8 | #endif | 9 | 9 |
| 10 | 10 | #define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \ | 11 | | - CO_FUTURE_WITH_STATEMENT) | | 11 | + CO_FUTURE_WITH_STATEMENT|CO_FUTURE_PRINT_FUNCTION) | 12 | 12 | #define PyCF_MASK_OBSOLETE (CO_NESTED) | 13 | 13 | #define PyCF_SOURCE_IS_UTF8 0x0100 | 14 | 14 | #define PyCF_DONT_IMPLY_DEDENT 0x0200 | |
Collapse file Copy file name to clipboardExpand all lines: Lib/__future__.py +6Lines changed: 6 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 53 | 53 | "division", | 54 | 54 | "absolute_import", | 55 | 55 | "with_statement", | | 56 | + "print_function", | 56 | 57 | ] | 57 | 58 |
| 58 | 59 | __all__ = ["all_feature_names"] + all_feature_names | | 66 | 67 | CO_FUTURE_DIVISION = 0x2000 # division | 67 | 68 | CO_FUTURE_ABSOLUTE_IMPORT = 0x4000 # perform absolute imports by default | 68 | 69 | CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement | | 70 | +CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function | 69 | 71 |
| 70 | 72 | class _Feature: | 71 | 73 | def __init__(self, optionalRelease, mandatoryRelease, compiler_flag): | @@ -114,3 +116,7 @@ def __repr__(self): | 114 | 116 | with_statement = _Feature((2, 5, 0, "alpha", 1), | 115 | 117 | (2, 6, 0, "alpha", 0), | 116 | 118 | CO_FUTURE_WITH_STATEMENT) | | 119 | + | | 120 | +print_function = _Feature((2, 6, 0, "alpha", 2), | | 121 | + (3, 0, 0, "alpha", 0), | | 122 | + CO_FUTURE_PRINT_FUNCTION) |
Collapse file Copy file name to clipboard +129Lines changed: 129 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +"""Test correct operation of the print function. | | 2 | +""" | | 3 | + | | 4 | +from __future__ import print_function | | 5 | + | | 6 | +import unittest | | 7 | +from test import test_support | | 8 | + | | 9 | +import sys | | 10 | +try: | | 11 | + # 3.x | | 12 | + from io import StringIO | | 13 | +except ImportError: | | 14 | + # 2.x | | 15 | + from StringIO import StringIO | | 16 | + | | 17 | +from contextlib import contextmanager | | 18 | + | | 19 | +NotDefined = object() | | 20 | + | | 21 | +# A dispatch table all 8 combinations of providing | | 22 | +# sep, end, and file | | 23 | +# I use this machinery so that I'm not just passing default | | 24 | +# values to print, I'm eiher passing or not passing in the | | 25 | +# arguments | | 26 | +dispatch = { | | 27 | + (False, False, False): | | 28 | + lambda args, sep, end, file: print(*args), | | 29 | + (False, False, True): | | 30 | + lambda args, sep, end, file: print(file=file, *args), | | 31 | + (False, True, False): | | 32 | + lambda args, sep, end, file: print(end=end, *args), | | 33 | + (False, True, True): | | 34 | + lambda args, sep, end, file: print(end=end, file=file, *args), | | 35 | + (True, False, False): | | 36 | + lambda args, sep, end, file: print(sep=sep, *args), | | 37 | + (True, False, True): | | 38 | + lambda args, sep, end, file: print(sep=sep, file=file, *args), | | 39 | + (True, True, False): | | 40 | + lambda args, sep, end, file: print(sep=sep, end=end, *args), | | 41 | + (True, True, True): | | 42 | + lambda args, sep, end, file: print(sep=sep, end=end, file=file, *args), | | 43 | + } | | 44 | + | | 45 | +@contextmanager | | 46 | +def stdout_redirected(new_stdout): | | 47 | + save_stdout = sys.stdout | | 48 | + sys.stdout = new_stdout | | 49 | + try: | | 50 | + yield None | | 51 | + finally: | | 52 | + sys.stdout = save_stdout | | 53 | + | | 54 | +# Class used to test __str__ and print | | 55 | +class ClassWith__str__: | | 56 | + def __init__(self, x): | | 57 | + self.x = x | | 58 | + def __str__(self): | | 59 | + return self.x | | 60 | + | | 61 | +class TestPrint(unittest.TestCase): | | 62 | + def check(self, expected, args, | | 63 | + sep=NotDefined, end=NotDefined, file=NotDefined): | | 64 | + # Capture sys.stdout in a StringIO. Call print with args, | | 65 | + # and with sep, end, and file, if they're defined. Result | | 66 | + # must match expected. | | 67 | + | | 68 | + # Look up the actual function to call, based on if sep, end, and file | | 69 | + # are defined | | 70 | + fn = dispatch[(sep is not NotDefined, | | 71 | + end is not NotDefined, | | 72 | + file is not NotDefined)] | | 73 | + | | 74 | + t = StringIO() | | 75 | + with stdout_redirected(t): | | 76 | + fn(args, sep, end, file) | | 77 | + | | 78 | + self.assertEqual(t.getvalue(), expected) | | 79 | + | | 80 | + def test_print(self): | | 81 | + def x(expected, args, sep=NotDefined, end=NotDefined): | | 82 | + # Run the test 2 ways: not using file, and using | | 83 | + # file directed to a StringIO | | 84 | + | | 85 | + self.check(expected, args, sep=sep, end=end) | | 86 | + | | 87 | + # When writing to a file, stdout is expected to be empty | | 88 | + o = StringIO() | | 89 | + self.check('', args, sep=sep, end=end, file=o) | | 90 | + | | 91 | + # And o will contain the expected output | | 92 | + self.assertEqual(o.getvalue(), expected) | | 93 | + | | 94 | + x('\n', ()) | | 95 | + x('a\n', ('a',)) | | 96 | + x('None\n', (None,)) | | 97 | + x('1 2\n', (1, 2)) | | 98 | + x('1 2\n', (1, ' ', 2)) | | 99 | + x('1*2\n', (1, 2), sep='*') | | 100 | + x('1 s', (1, 's'), end='') | | 101 | + x('a\nb\n', ('a', 'b'), sep='\n') | | 102 | + x('1.01', (1.0, 1), sep='', end='') | | 103 | + x('1*a*1.3+', (1, 'a', 1.3), sep='*', end='+') | | 104 | + x('a\n\nb\n', ('a\n', 'b'), sep='\n') | | 105 | + x('\0+ +\0\n', ('\0', ' ', '\0'), sep='+') | | 106 | + | | 107 | + x('a\n b\n', ('a\n', 'b')) | | 108 | + x('a\n b\n', ('a\n', 'b'), sep=None) | | 109 | + x('a\n b\n', ('a\n', 'b'), end=None) | | 110 | + x('a\n b\n', ('a\n', 'b'), sep=None, end=None) | | 111 | + | | 112 | + x('*\n', (ClassWith__str__('*'),)) | | 113 | + x('abc 1\n', (ClassWith__str__('abc'), 1)) | | 114 | + | | 115 | + # 2.x unicode tests | | 116 | + x(u'1 2\n', ('1', u'2')) | | 117 | + x(u'u\1234\n', (u'u\1234',)) | | 118 | + x(u' abc 1\n', (' ', ClassWith__str__(u'abc'), 1)) | | 119 | + | | 120 | + # errors | | 121 | + self.assertRaises(TypeError, print, '', sep=3) | | 122 | + self.assertRaises(TypeError, print, '', end=3) | | 123 | + self.assertRaises(AttributeError, print, '', file='') | | 124 | + | | 125 | +def test_main(): | | 126 | + test_support.run_unittest(TestPrint) | | 127 | + | | 128 | +if __name__ == "__main__": | | 129 | + test_main() |
Collapse file Copy file name to clipboardExpand all lines: Misc/ACKS +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -622,6 +622,7 @@ George Sipe | 622 | 622 | J. Sipprell | 623 | 623 | Kragen Sitaker | 624 | 624 | Christopher Smith | | 625 | +Eric V. Smith | 625 | 626 | Gregory P. Smith | 626 | 627 | Rafal Smotrzyk | 627 | 628 | Dirk Soede | |
Collapse file Copy file name to clipboardExpand all lines: Misc/NEWS +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 2? | 12 | 12 | Core and builtins | 13 | 13 | ----------------- | 14 | 14 |
| | 15 | +- Issue 1745. Backport print function with: | | 16 | + from __future__ import print_function | | 17 | + | 15 | 18 | - Issue 2332: add new attribute names for instance method objects. | 16 | 19 | The two changes are: im_self -> __self__ and im_func -> __func__ | 17 | 20 |
| |
Collapse file Copy file name to clipboardExpand all lines: Parser/parser.c +8-6Lines changed: 8 additions & 6 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -149,12 +149,10 @@ classify(parser_state *ps, int type, char *str) | 149 | 149 | strcmp(l->lb_str, s) != 0) | 150 | 150 | continue; | 151 | 151 | #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD | 152 | | - if (!(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) { | 153 | | - if (s[0] == 'w' && strcmp(s, "with") == 0) | 154 | | - break; /* not a keyword yet */ | 155 | | - else if (s[0] == 'a' && strcmp(s, "as") == 0) | 156 | | - break; /* not a keyword yet */ | 157 | | - } | | 152 | + if (ps->p_flags & CO_FUTURE_PRINT_FUNCTION && | | 153 | + s[0] == 'p' && strcmp(s, "print") == 0) { | | 154 | + break; /* no longer a keyword */ | | 155 | + } | 158 | 156 | #endif | 159 | 157 | D(printf("It's a keyword\n")); | 160 | 158 | return n - i; | @@ -208,6 +206,10 @@ future_hack(parser_state *ps) | 208 | 206 | strcmp(STR(CHILD(cch, 0)), "with_statement") == 0) { | 209 | 207 | ps->p_flags |= CO_FUTURE_WITH_STATEMENT; | 210 | 208 | break; | | 209 | + } else if (NCH(cch) >= 1 && TYPE(CHILD(cch, 0)) == NAME && | | 210 | + strcmp(STR(CHILD(cch, 0)), "print_function") == 0) { | | 211 | + ps->p_flags |= CO_FUTURE_PRINT_FUNCTION; | | 212 | + break; | 211 | 213 | } | 212 | 214 | } | 213 | 215 | } | |
Collapse file Copy file name to clipboardExpand all lines: Parser/parsetok.c +2-22Lines changed: 2 additions & 22 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -123,8 +123,8 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, | 123 | 123 | return NULL; | 124 | 124 | } | 125 | 125 | #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD | 126 | | - if (flags & PyPARSE_WITH_IS_KEYWORD) | 127 | | - ps->p_flags |= CO_FUTURE_WITH_STATEMENT; | | 126 | + if (flags & PyPARSE_PRINT_IS_FUNCTION) | | 127 | + ps->p_flags |= CO_FUTURE_PRINT_FUNCTION; | 128 | 128 | #endif | 129 | 129 |
| 130 | 130 | for (;;) { | @@ -167,26 +167,6 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, | 167 | 167 | str[len] = '\0'; | 168 | 168 |
| 169 | 169 | #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD | 170 | | - /* This is only necessary to support the "as" warning, but | 171 | | - we don't want to warn about "as" in import statements. */ | 172 | | - if (type == NAME && | 173 | | - len == 6 && str[0] == 'i' && strcmp(str, "import") == 0) | 174 | | - handling_import = 1; | 175 | | - | 176 | | - /* Warn about with as NAME */ | 177 | | - if (type == NAME && | 178 | | - !(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) { | 179 | | - if (len == 4 && str[0] == 'w' && strcmp(str, "with") == 0) | 180 | | - warn(with_msg, err_ret->filename, tok->lineno); | 181 | | - else if (!(handling_import || handling_with) && | 182 | | - len == 2 && str[0] == 'a' && | 183 | | - strcmp(str, "as") == 0) | 184 | | - warn(as_msg, err_ret->filename, tok->lineno); | 185 | | - } | 186 | | - else if (type == NAME && | 187 | | - (ps->p_flags & CO_FUTURE_WITH_STATEMENT) && | 188 | | - len == 4 && str[0] == 'w' && strcmp(str, "with") == 0) | 189 | | - handling_with = 1; | 190 | 170 | #endif | 191 | 171 | if (a >= tok->line_start) | 192 | 172 | col_offset = a - tok->line_start; | |
|