Fixed #27600 -- Suppressed the REPL during shell's reading from stdin.

Thanks Adam Chainz for review and guidance.
This commit is contained in:
jpic 2016-12-13 01:36:08 +01:00 committed by Tim Graham
parent 24fa728a47
commit bf6392bb75
3 changed files with 44 additions and 3 deletions

View File

@ -1,4 +1,6 @@
import os
import select
import sys
import warnings
from django.core.management.base import BaseCommand
@ -7,7 +9,12 @@ from django.utils.deprecation import RemovedInDjango20Warning
class Command(BaseCommand):
help = "Runs a Python interactive interpreter. Tries to use IPython or bpython, if one of them is available."
help = (
"Runs a Python interactive interpreter. Tries to use IPython or "
"bpython, if one of them is available. Any standard input is executed "
"as code."
)
requires_system_checks = False
shells = ['ipython', 'bpython', 'python']
@ -114,6 +121,12 @@ class Command(BaseCommand):
exec(options['command'])
return
# Execute stdin if it has anything to read and exit.
# Not supported on Windows due to select.select() limitations.
if sys.platform != 'win32' and select.select([sys.stdin], [], [], 0)[0]:
exec(sys.stdin.read())
return
available_shells = [options['interface']] if options['interface'] else self.shells
for shell in available_shells:

View File

@ -979,6 +979,22 @@ Lets you pass a command as a string to execute it as Django, like so::
django-admin shell --command="import django; print(django.__version__)"
You can also pass code in on standard input to execute it. For example:
.. code-block:: console
$ django-admin shell <<EOF
> import django
> print(django.__version__)
> EOF
On Windows, the REPL is output due to implementation limits of
:func:`select.select` on that platform.
.. versionchanged:: 1.11
In older versions, the REPL is also output on UNIX systems.
``showmigrations``
------------------

View File

@ -1,7 +1,10 @@
import sys
import unittest
from django import __version__
from django.core.management import call_command
from django.test import SimpleTestCase
from django.test.utils import patch_logger
from django.test import SimpleTestCase, mock
from django.test.utils import captured_stdin, captured_stdout, patch_logger
class ShellCommandTestCase(SimpleTestCase):
@ -17,3 +20,12 @@ class ShellCommandTestCase(SimpleTestCase):
)
self.assertEqual(len(logger), 1)
self.assertEqual(logger[0], __version__)
@unittest.skipIf(sys.platform == 'win32', "Windows select() doesn't support file descriptors.")
@mock.patch('django.core.management.commands.shell.select')
def test_stdin_read(self, select):
with captured_stdin() as stdin, captured_stdout() as stdout:
stdin.write('print(100)\n')
stdin.seek(0)
call_command('shell')
self.assertEqual(stdout.getvalue().strip(), '100')