Code

Ticket #12221: full_completion.diff

File full_completion.diff, 6.8 KB (added by ericholscher, 5 years ago)

All of the work I've done thus far for this ticket.

Line 
1diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
2index 60dcf72..5432ef4 100644
3--- a/django/core/management/__init__.py
4+++ b/django/core/management/__init__.py
5@@ -327,6 +327,21 @@ class ManagementUtility(object):
6             prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
7             options = filter(lambda (x, v): x not in prev_opts, options)
8 
9+            if hasattr(subcommand_cls, 'complete'):
10+                complete = subcommand_cls.complete()
11+                if isinstance(complete, list):
12+                    options += [(k, 0) for k in complete]
13+                elif isinstance(complete, dict):
14+                    to_add = complete[str(cword-2)]
15+                    if to_add == 'COMMAND_NAME':
16+                        print ' '.join(filter(lambda x: x.startswith(curr), subcommands))
17+                    elif to_add == 'APP_NAME':
18+                        from django.conf import settings
19+                        options += [(a.split('.')[-1], 0) for a in settings.INSTALLED_APPS]
20+                    else:
21+                        options += to_add
22+
23+
24             # filter options by current input
25             options = [(k, v) for k, v in options if k.startswith(curr)]
26             for option in options:
27diff --git a/tests/regressiontests/bash_completion/__init__.py b/tests/regressiontests/bash_completion/__init__.py
28new file mode 100644
29index 0000000..e69de29
30diff --git a/tests/regressiontests/bash_completion/management/__init__.py b/tests/regressiontests/bash_completion/management/__init__.py
31new file mode 100644
32index 0000000..e69de29
33diff --git a/tests/regressiontests/bash_completion/management/commands/__init__.py b/tests/regressiontests/bash_completion/management/commands/__init__.py
34new file mode 100644
35index 0000000..e69de29
36diff --git a/tests/regressiontests/bash_completion/management/commands/dict_command.py b/tests/regressiontests/bash_completion/management/commands/dict_command.py
37new file mode 100644
38index 0000000..d7f0979
39--- /dev/null
40+++ b/tests/regressiontests/bash_completion/management/commands/dict_command.py
41@@ -0,0 +1,20 @@
42+import sys, os
43+from optparse import OptionParser, make_option
44+
45+from django.core.management.base import BaseCommand
46+
47+class Command(BaseCommand):
48+    option_list = BaseCommand.option_list + (
49+        make_option("--list", action="store_true", dest="list",
50+                    help="Print all options"),
51+    )
52+
53+    def complete(self):
54+        return {
55+            '0': [('awesome', None), ('sweet', None)],
56+            '1': 'COMMAND_NAME',
57+            '2': 'APP_NAME',
58+        }
59+
60+    def handle(self, *args, **options):
61+        pass
62diff --git a/tests/regressiontests/bash_completion/management/commands/test_command.py b/tests/regressiontests/bash_completion/management/commands/test_command.py
63new file mode 100644
64index 0000000..2b9ec0f
65--- /dev/null
66+++ b/tests/regressiontests/bash_completion/management/commands/test_command.py
67@@ -0,0 +1,16 @@
68+import sys, os
69+from optparse import OptionParser, make_option
70+
71+from django.core.management.base import BaseCommand
72+
73+class Command(BaseCommand):
74+    option_list = BaseCommand.option_list + (
75+        make_option("--list", action="store_true", dest="list",
76+                    help="Print all options"),
77+    )
78+
79+    def complete(self):
80+        return ['awesome', 'sweet']
81+
82+    def handle(self, *args, **options):
83+        pass
84diff --git a/tests/regressiontests/bash_completion/models.py b/tests/regressiontests/bash_completion/models.py
85new file mode 100644
86index 0000000..e69de29
87diff --git a/tests/regressiontests/bash_completion/tests.py b/tests/regressiontests/bash_completion/tests.py
88new file mode 100644
89index 0000000..e751bee
90--- /dev/null
91+++ b/tests/regressiontests/bash_completion/tests.py
92@@ -0,0 +1,90 @@
93+"""
94+A series of tests to establish that the command-line bash completion works.
95+"""
96+import os
97+import unittest
98+import sys
99+import StringIO
100+
101+from django.core.management import ManagementUtility
102+
103+class BashCompletionTests(unittest.TestCase):
104+    """
105+    Testing the Python level bash completion code.
106+    This requires settings up the environment like if we got passed data
107+    from bash.
108+    """
109+
110+    def setUp(self):
111+        os.environ['DJANGO_AUTO_COMPLETE'] = '1'
112+        self.output = StringIO.StringIO()
113+        self.old_stdout = sys.stdout
114+        sys.stdout = self.output
115+
116+    def tearDown(self):
117+        sys.stdout = self.old_stdout
118+
119+    def _user_input(self, input_str):
120+        os.environ['COMP_WORDS'] = input_str
121+        os.environ['COMP_CWORD'] = str(len(input_str.split()) - 1)
122+        sys.argv = input_str.split(' ')
123+
124+    def _run_autocomplete(self):
125+        util = ManagementUtility(argv=sys.argv)
126+        try:
127+            util.autocomplete()
128+        except SystemExit:
129+            pass
130+        return self.output.getvalue().strip().split('\n')
131+
132+    def test_django_admin_py(self):
133+        self._user_input('django-admin.py sqlall --v')
134+        output = self._run_autocomplete()
135+        self.assertEqual(output, ['--verbosity='])
136+
137+    def test_manage_py(self):
138+        self._user_input('manage.py sqlall --v')
139+        output = self._run_autocomplete()
140+        self.assertEqual(output, ['--verbosity='])
141+
142+    def test_custom_command(self):
143+        self._user_input('django-admin.py test_command --l')
144+        output = self._run_autocomplete()
145+        self.assertEqual(output, ['--list'])
146+
147+    def test_subcommands(self):
148+        self._user_input('django-admin.py sql')
149+        output = self._run_autocomplete()
150+        self.assertEqual(output, ['sqlinitialdata sqlclear sqlreset sqlsequencereset sql sqlall sqlflush sqlcustom sqlindexes'])
151+
152+    def test_help(self):
153+        #Help should return nothing since it takes no args.
154+        self._user_input('django-admin.py help --')
155+        output = self._run_autocomplete()
156+        self.assertEqual(output, [''])
157+
158+    def test_runfcgi(self):
159+        #runfcgi has its own special options
160+        self._user_input('django-admin.py runfcgi h')
161+        output = self._run_autocomplete()
162+        self.assertEqual(output, ['host='])
163+
164+    def test_app_completion(self):
165+        self._user_input('django-admin.py sqlall a')
166+        output = self._run_autocomplete()
167+        self.assertEqual(output, ['auth', 'admin'])
168+
169+    def test_dict_return_list(self):
170+        self._user_input('django-admin.py dict_command a')
171+        output = self._run_autocomplete()
172+        self.assertEqual(output, ['awesome'])
173+
174+    def test_dict_return_commands(self):
175+        self._user_input('django-admin.py dict_command awesome sqlal')
176+        output = self._run_autocomplete()
177+        self.assertEqual(output, ['sqlall'])
178+
179+    def test_dict_return_apps(self):
180+        self._user_input('django-admin.py dict_command awesome sqlall a')
181+        output = self._run_autocomplete()
182+        self.assertEqual(output, ['auth', 'admin'])