Skip to content

Commit a67b7dd

Browse files
author
Wren Turkal
committed
Add file args to input builtin.
This is a change to add support for overriding input, output, and error files used by the input builtin. See https://bugs.python.org/issue31603 for more.
1 parent a106aec commit a67b7dd

File tree

3 files changed

+46
-14
lines changed

3 files changed

+46
-14
lines changed

Lib/test/test_builtin.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,23 @@ def child(wpipe):
16281628
)
16291629
self.assertSequenceEqual(lines, expected)
16301630

1631+
def test_input_override_stdin(self):
1632+
input_buf = io.StringIO('quux\n')
1633+
input_received = input(infile=input_buf)
1634+
self.assertSequenceEqual('quux', input_received)
1635+
1636+
def test_input_override_stdout(self):
1637+
output_buf = io.StringIO()
1638+
input_buf = io.StringIO('\n')
1639+
input('blah: ', infile=input_buf, outfile=output_buf)
1640+
self.assertSequenceEqual('blah: ', output_buf.getvalue())
1641+
1642+
def test_input_override_stderr(self):
1643+
error_buf = io.StringIO()
1644+
input_buf = io.StringIO('\n')
1645+
self.assertRaises(RuntimeError, input, 'blah: ', infile=input_buf,
1646+
outfile=None, errfile=error_buf)
1647+
16311648
class TestSorted(unittest.TestCase):
16321649

16331650
def test_basic(self):

Python/bltinmodule.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,23 +1842,30 @@ input as builtin_input
18421842
18431843
prompt: object(c_default="NULL") = None
18441844
/
1845+
*
1846+
infile: object(c_default="_PySys_GetObjectId(&PyId_stdin)") = None
1847+
outfile: object(c_default="_PySys_GetObjectId(&PyId_stdout)") = None
1848+
errfile: object(c_default="_PySys_GetObjectId(&PyId_stderr)") = None
18451849
18461850
Read a string from standard input. The trailing newline is stripped.
18471851
18481852
The prompt string, if given, is printed to standard output without a
18491853
trailing newline before reading input.
1854+
The defaults for infile, outfile, and errfile if they not provided are equivalent
1855+
to sys.stdin, sys.stdout, and sys.stderr respectively.
18501856
18511857
If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
18521858
On *nix systems, readline is used if available.
18531859
[clinic start generated code]*/
18541860

18551861
static PyObject *
1856-
builtin_input_impl(PyObject *module, PyObject *prompt)
1857-
/*[clinic end generated code: output=83db5a191e7a0d60 input=5e8bb70c2908fe3c]*/
1862+
builtin_input_impl(PyObject *module, PyObject *prompt, PyObject *infile,
1863+
PyObject *outfile, PyObject *errfile)
1864+
/*[clinic end generated code: output=40acdfd4ce9e4222 input=f7d6c671b75027bc]*/
18581865
{
1859-
PyObject *fin = _PySys_GetObjectId(&PyId_stdin);
1860-
PyObject *fout = _PySys_GetObjectId(&PyId_stdout);
1861-
PyObject *ferr = _PySys_GetObjectId(&PyId_stderr);
1866+
PyObject *fin = infile;
1867+
PyObject *fout = outfile;
1868+
PyObject *ferr = errfile;
18621869
PyObject *tmp;
18631870
long fd;
18641871
int tty;

Python/clinic/bltinmodule.c.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -528,35 +528,43 @@ builtin_pow(PyObject *module, PyObject **args, Py_ssize_t nargs)
528528
}
529529

530530
PyDoc_STRVAR(builtin_input__doc__,
531-
"input($module, prompt=None, /)\n"
531+
"input($module, prompt=None, /, *, infile=None, outfile=None,\n"
532+
" errfile=None)\n"
532533
"--\n"
533534
"\n"
534535
"Read a string from standard input. The trailing newline is stripped.\n"
535536
"\n"
536537
"The prompt string, if given, is printed to standard output without a\n"
537538
"trailing newline before reading input.\n"
539+
"The defaults for infile, outfile, and errfile if they not provided are equivalent\n"
540+
"to sys.stdin, sys.stdout, and sys.stderr respectively.\n"
538541
"\n"
539542
"If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.\n"
540543
"On *nix systems, readline is used if available.");
541544

542545
#define BUILTIN_INPUT_METHODDEF \
543-
{"input", (PyCFunction)builtin_input, METH_FASTCALL, builtin_input__doc__},
546+
{"input", (PyCFunction)builtin_input, METH_FASTCALL|METH_KEYWORDS, builtin_input__doc__},
544547

545548
static PyObject *
546-
builtin_input_impl(PyObject *module, PyObject *prompt);
549+
builtin_input_impl(PyObject *module, PyObject *prompt, PyObject *infile,
550+
PyObject *outfile, PyObject *errfile);
547551

548552
static PyObject *
549-
builtin_input(PyObject *module, PyObject **args, Py_ssize_t nargs)
553+
builtin_input(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
550554
{
551555
PyObject *return_value = NULL;
556+
static const char * const _keywords[] = {"", "infile", "outfile", "errfile", NULL};
557+
static _PyArg_Parser _parser = {"|O$OOO:input", _keywords, 0};
552558
PyObject *prompt = NULL;
559+
PyObject *infile = _PySys_GetObjectId(&PyId_stdin);
560+
PyObject *outfile = _PySys_GetObjectId(&PyId_stdout);
561+
PyObject *errfile = _PySys_GetObjectId(&PyId_stderr);
553562

554-
if (!_PyArg_UnpackStack(args, nargs, "input",
555-
0, 1,
556-
&prompt)) {
563+
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
564+
&prompt, &infile, &outfile, &errfile)) {
557565
goto exit;
558566
}
559-
return_value = builtin_input_impl(module, prompt);
567+
return_value = builtin_input_impl(module, prompt, infile, outfile, errfile);
560568

561569
exit:
562570
return return_value;
@@ -676,4 +684,4 @@ builtin_issubclass(PyObject *module, PyObject **args, Py_ssize_t nargs)
676684
exit:
677685
return return_value;
678686
}
679-
/*[clinic end generated code: output=09752daa8cdd6ec7 input=a9049054013a1b77]*/
687+
/*[clinic end generated code: output=4ca8e7840e9e74f3 input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)