瀏覽代碼

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

Thanks Adam Chainz for review and guidance.
jpic 8 年之前
父節點
當前提交
bf6392bb75
共有 3 個文件被更改,包括 44 次插入3 次删除
  1. 14 1
      django/core/management/commands/shell.py
  2. 16 0
      docs/ref/django-admin.txt
  3. 14 2
      tests/shell/tests.py

+ 14 - 1
django/core/management/commands/shell.py

@@ -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:

+ 16 - 0
docs/ref/django-admin.txt

@@ -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``
 ------------------
 

+ 14 - 2
tests/shell/tests.py

@@ -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')