1. import sys
    
  2. import unittest
    
  3. from unittest import mock
    
  4. 
    
  5. from django import __version__
    
  6. from django.core.management import CommandError, call_command
    
  7. from django.test import SimpleTestCase
    
  8. from django.test.utils import captured_stdin, captured_stdout
    
  9. 
    
  10. 
    
  11. class ShellCommandTestCase(SimpleTestCase):
    
  12.     script_globals = 'print("__name__" in globals())'
    
  13.     script_with_inline_function = (
    
  14.         "import django\ndef f():\n    print(django.__version__)\nf()"
    
  15.     )
    
  16. 
    
  17.     def test_command_option(self):
    
  18.         with self.assertLogs("test", "INFO") as cm:
    
  19.             call_command(
    
  20.                 "shell",
    
  21.                 command=(
    
  22.                     "import django; from logging import getLogger; "
    
  23.                     'getLogger("test").info(django.__version__)'
    
  24.                 ),
    
  25.             )
    
  26.         self.assertEqual(cm.records[0].getMessage(), __version__)
    
  27. 
    
  28.     def test_command_option_globals(self):
    
  29.         with captured_stdout() as stdout:
    
  30.             call_command("shell", command=self.script_globals)
    
  31.         self.assertEqual(stdout.getvalue().strip(), "True")
    
  32. 
    
  33.     def test_command_option_inline_function_call(self):
    
  34.         with captured_stdout() as stdout:
    
  35.             call_command("shell", command=self.script_with_inline_function)
    
  36.         self.assertEqual(stdout.getvalue().strip(), __version__)
    
  37. 
    
  38.     @unittest.skipIf(
    
  39.         sys.platform == "win32", "Windows select() doesn't support file descriptors."
    
  40.     )
    
  41.     @mock.patch("django.core.management.commands.shell.select")
    
  42.     def test_stdin_read(self, select):
    
  43.         with captured_stdin() as stdin, captured_stdout() as stdout:
    
  44.             stdin.write("print(100)\n")
    
  45.             stdin.seek(0)
    
  46.             call_command("shell")
    
  47.         self.assertEqual(stdout.getvalue().strip(), "100")
    
  48. 
    
  49.     @unittest.skipIf(
    
  50.         sys.platform == "win32",
    
  51.         "Windows select() doesn't support file descriptors.",
    
  52.     )
    
  53.     @mock.patch("django.core.management.commands.shell.select")  # [1]
    
  54.     def test_stdin_read_globals(self, select):
    
  55.         with captured_stdin() as stdin, captured_stdout() as stdout:
    
  56.             stdin.write(self.script_globals)
    
  57.             stdin.seek(0)
    
  58.             call_command("shell")
    
  59.         self.assertEqual(stdout.getvalue().strip(), "True")
    
  60. 
    
  61.     @unittest.skipIf(
    
  62.         sys.platform == "win32",
    
  63.         "Windows select() doesn't support file descriptors.",
    
  64.     )
    
  65.     @mock.patch("django.core.management.commands.shell.select")  # [1]
    
  66.     def test_stdin_read_inline_function_call(self, select):
    
  67.         with captured_stdin() as stdin, captured_stdout() as stdout:
    
  68.             stdin.write(self.script_with_inline_function)
    
  69.             stdin.seek(0)
    
  70.             call_command("shell")
    
  71.         self.assertEqual(stdout.getvalue().strip(), __version__)
    
  72. 
    
  73.     @mock.patch("django.core.management.commands.shell.select.select")  # [1]
    
  74.     @mock.patch.dict("sys.modules", {"IPython": None})
    
  75.     def test_shell_with_ipython_not_installed(self, select):
    
  76.         select.return_value = ([], [], [])
    
  77.         with self.assertRaisesMessage(
    
  78.             CommandError, "Couldn't import ipython interface."
    
  79.         ):
    
  80.             call_command("shell", interface="ipython")
    
  81. 
    
  82.     @mock.patch("django.core.management.commands.shell.select.select")  # [1]
    
  83.     @mock.patch.dict("sys.modules", {"bpython": None})
    
  84.     def test_shell_with_bpython_not_installed(self, select):
    
  85.         select.return_value = ([], [], [])
    
  86.         with self.assertRaisesMessage(
    
  87.             CommandError, "Couldn't import bpython interface."
    
  88.         ):
    
  89.             call_command("shell", interface="bpython")
    
  90. 
    
  91.     # [1] Patch select to prevent tests failing when when the test suite is run
    
  92.     # in parallel mode. The tests are run in a subprocess and the subprocess's
    
  93.     # stdin is closed and replaced by /dev/null. Reading from /dev/null always
    
  94.     # returns EOF and so select always shows that sys.stdin is ready to read.
    
  95.     # This causes problems because of the call to select.select() toward the
    
  96.     # end of shell's handle() method.