Repository: adamchainz/django-rich (language: python)

Issue:
Pretty install on 'manage.py shell'
### Description

Rich has "pretty" mode that can be installed in the plain python repl, and in ipython:

https://rich.readthedocs.io/en/latest/introduction.html?highlight=install#rich-in-the-repl

We could extend `manage.py shell` to use that automatically.


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ceed0cf..b58878c 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,11 @@
 Changelog
 =========
 
+* Add a ``shell`` command extension that enables Rich’s pretty-printing.
+  Activate this feature by adding ``django_rich`` to your ``INSTALLED_APPS`` setting.
+
+  Thanks to q0w in `PR #78 <https://github.com/adamchainz/django-rich/pull/78>`__.
+
 1.9.0 (2024-06-19)
 ------------------
 
diff --git a/README.rst b/README.rst
index 28489f7..c03fcc5 100644
--- a/README.rst
+++ b/README.rst
@@ -49,6 +49,25 @@ Follow the documentation below to use them.
 Reference
 ---------
 
+``shell`` command integration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+django-rich has an extended version of Django’s built-in |shell command|__ that enables `Rich’s pretty-printing <https://rich.readthedocs.io/en/stable/introduction.html?highlight=install#rich-in-the-repl>`__.
+To activate this feature, add ``django_rich`` to your ``INSTALLED_APPS`` setting:
+
+.. |shell command| replace:: ``shell`` command
+__ https://docs.djangoproject.com/en/stable/ref/django-admin/#shell
+
+   .. code-block:: python
+
+       INSTALLED_APPS = [
+           ...,
+           "django_rich",
+           ...,
+       ]
+
+This feature only affects the Python and bypthon interpreters, not IPython.
+
 ``django_rich.management.RichCommand``
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/src/django_rich/management.py b/src/django_rich/management/__init__.py
similarity index 100%
rename from src/django_rich/management.py
rename to src/django_rich/management/__init__.py
diff --git a/src/django_rich/management/commands/__init__.py b/src/django_rich/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/django_rich/management/commands/shell.py b/src/django_rich/management/commands/shell.py
new file mode 100644
index 0000000..7595a18
--- /dev/null
+++ b/src/django_rich/management/commands/shell.py
@@ -0,0 +1,12 @@
+from __future__ import annotations
+
+from typing import Any
+
+from django.core.management.commands.shell import Command as BaseCommand
+from rich import pretty
+
+
+class Command(BaseCommand):
+    def handle(self, **options: Any) -> None:
+        pretty.install()
+        return super().handle(**options)


Test patch:
diff --git a/tests/settings.py b/tests/settings.py
index 9cabb70..11e7569 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -16,6 +16,7 @@
 DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
 
 INSTALLED_APPS = [
+    "django_rich",
     "tests.testapp",
 ]
 
diff --git a/tests/test_shell.py b/tests/test_shell.py
new file mode 100644
index 0000000..b5659b4
--- /dev/null
+++ b/tests/test_shell.py
@@ -0,0 +1,31 @@
+from __future__ import annotations
+
+import sys
+from code import InteractiveConsole
+from unittest import mock
+
+import pytest
+from django.core.management import call_command
+from django.test import SimpleTestCase
+from django.test.utils import captured_stdin
+from django.test.utils import captured_stdout
+
+
+class ShellCommandTestCase(SimpleTestCase):
+    @pytest.mark.skipif(
+        sys.platform == "win32",
+        reason="Windows select() doesn't support file descriptors.",
+    )
+    @mock.patch("django.core.management.commands.shell.select")
+    def test_pretty(self, select):
+        console = InteractiveConsole()
+        with captured_stdin() as _, captured_stdout() as stdout:
+            call_command("shell", "-i", "python")
+            console.push("from rich.panel import Panel\n")
+            console.push('Panel.fit("hi!")\n')
+        lines = stdout.getvalue().splitlines()
+        assert lines == [
+            "╭─────╮",
+            "│ hi! │",
+            "╰─────╯",
+        ]