Commit bc3b6829 authored by Georg Brandl's avatar Georg Brandl

Closes #13761: add a "flush" keyword argument to print().

parent 5136ac0c
...@@ -946,7 +946,7 @@ are always available. They are listed here in alphabetical order. ...@@ -946,7 +946,7 @@ are always available. They are listed here in alphabetical order.
must be of integer types, and *y* must be non-negative. must be of integer types, and *y* must be non-negative.
.. function:: print([object, ...], *, sep=' ', end='\\n', file=sys.stdout) .. function:: print([object, ...], *, sep=' ', end='\\n', file=sys.stdout, flush=False)
Print *object*\(s) to the stream *file*, separated by *sep* and followed by Print *object*\(s) to the stream *file*, separated by *sep* and followed by
*end*. *sep*, *end* and *file*, if present, must be given as keyword *end*. *sep*, *end* and *file*, if present, must be given as keyword
...@@ -959,9 +959,12 @@ are always available. They are listed here in alphabetical order. ...@@ -959,9 +959,12 @@ are always available. They are listed here in alphabetical order.
*end*. *end*.
The *file* argument must be an object with a ``write(string)`` method; if it The *file* argument must be an object with a ``write(string)`` method; if it
is not present or ``None``, :data:`sys.stdout` will be used. Output buffering is not present or ``None``, :data:`sys.stdout` will be used. Whether output
is determined by *file*. Use ``file.flush()`` to ensure, for instance, is buffered is usually determined by *file*, but if the *flush* keyword
immediate appearance on a screen. argument is true, the stream is forcibly flushed.
.. versionchanged:: 3.3
Added the *flush* keyword argument.
.. function:: property(fget=None, fset=None, fdel=None, doc=None) .. function:: property(fget=None, fset=None, fdel=None, doc=None)
......
...@@ -111,6 +111,32 @@ class TestPrint(unittest.TestCase): ...@@ -111,6 +111,32 @@ class TestPrint(unittest.TestCase):
self.assertRaises(TypeError, print, '', end=3) self.assertRaises(TypeError, print, '', end=3)
self.assertRaises(AttributeError, print, '', file='') self.assertRaises(AttributeError, print, '', file='')
def test_print_flush(self):
# operation of the flush flag
class filelike():
def __init__(self):
self.written = ''
self.flushed = 0
def write(self, str):
self.written += str
def flush(self):
self.flushed += 1
f = filelike()
print(1, file=f, end='', flush=True)
print(2, file=f, end='', flush=True)
print(3, file=f, flush=False)
self.assertEqual(f.written, '123\n')
self.assertEqual(f.flushed, 2)
# ensure exceptions from flush are passed through
class noflush():
def write(self, str):
pass
def flush(self):
raise RuntimeError
self.assertRaises(RuntimeError, print, 1, file=noflush(), flush=True)
def test_main(): def test_main():
support.run_unittest(TestPrint) support.run_unittest(TestPrint)
......
...@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1? ...@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #13761: Add a "flush" keyword argument to the print() function,
used to ensure flushing the output stream.
- Issue #13645: pyc files now contain the size of the corresponding source - Issue #13645: pyc files now contain the size of the corresponding source
code, to avoid timestamp collisions (especially on filesystems with a low code, to avoid timestamp collisions (especially on filesystems with a low
timestamp resolution) when checking for freshness of the bytecode. timestamp resolution) when checking for freshness of the bytecode.
......
...@@ -1484,15 +1484,15 @@ equivalent to (x**y) % z, but may be more efficient (e.g. for longs)."); ...@@ -1484,15 +1484,15 @@ equivalent to (x**y) % z, but may be more efficient (e.g. for longs).");
static PyObject * static PyObject *
builtin_print(PyObject *self, PyObject *args, PyObject *kwds) builtin_print(PyObject *self, PyObject *args, PyObject *kwds)
{ {
static char *kwlist[] = {"sep", "end", "file", 0}; static char *kwlist[] = {"sep", "end", "file", "flush", 0};
static PyObject *dummy_args; static PyObject *dummy_args;
PyObject *sep = NULL, *end = NULL, *file = NULL; PyObject *sep = NULL, *end = NULL, *file = NULL, *flush = NULL;
int i, err; int i, err;
if (dummy_args == NULL && !(dummy_args = PyTuple_New(0))) if (dummy_args == NULL && !(dummy_args = PyTuple_New(0)))
return NULL; return NULL;
if (!PyArg_ParseTupleAndKeywords(dummy_args, kwds, "|OOO:print", if (!PyArg_ParseTupleAndKeywords(dummy_args, kwds, "|OOOO:print",
kwlist, &sep, &end, &file)) kwlist, &sep, &end, &file, &flush))
return NULL; return NULL;
if (file == NULL || file == Py_None) { if (file == NULL || file == Py_None) {
file = PySys_GetObject("stdout"); file = PySys_GetObject("stdout");
...@@ -1543,6 +1543,20 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -1543,6 +1543,20 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds)
if (err) if (err)
return NULL; return NULL;
if (flush != NULL) {
PyObject *tmp;
int do_flush = PyObject_IsTrue(flush);
if (do_flush == -1)
return NULL;
else if (do_flush) {
tmp = PyObject_CallMethod(file, "flush", "");
if (tmp == NULL)
return NULL;
else
Py_DECREF(tmp);
}
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment