Skip to content

Commit 9fb94db

Browse files
committed
implement #81
1 parent 644fa49 commit 9fb94db

File tree

8 files changed

+3173
-3163
lines changed

8 files changed

+3173
-3163
lines changed

django_typer/__init__.py

Lines changed: 17 additions & 3154 deletions
Large diffs are not rendered by default.

django_typer/management/__init__.py

Lines changed: 3105 additions & 0 deletions
Large diffs are not rendered by default.

django_typer/management/commands/shellcompletion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
completion_init, # pyright: ignore[reportPrivateImportUsage]
5555
)
5656

57-
from django_typer import TyperCommand, command, get_command
57+
from django_typer.management import TyperCommand, command, get_command
5858
from django_typer.utils import get_usage_script
5959

6060
DETECTED_SHELL = None

doc/source/architecture.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,42 @@ present. This is ok, the ones added last will be used.
156156
@grp2.command()
157157
def cmd2():
158158
pass
159+
160+
161+
Notes on BaseCommand_
162+
~~~~~~~~~~~~~~~~~~~~~
163+
164+
There are a number of encumbrances in the Django management command design that make our
165+
implementation more difficult than it need be. We document them here mostly to keep track of them
166+
for potential future core Django work.
167+
168+
1) BaseCommand::execute() prints results to stdout without attempting to convert them
169+
to strings. This means you've gotta do weird stuff to get a return object out of
170+
call_command()
171+
172+
2) call_command() converts arguments to strings. There is no official way to pass
173+
previously parsed arguments through call_command(). This makes it a bit awkward to
174+
use management commands as callable functions in django code which you should be able
175+
to easily do. django-typer allows you to invoke the command and group functions
176+
directly so you can work around this, but it would be nice if call_command() supported
177+
a general interface that all command libraries could easily implement to.
178+
179+
3) terminal autocompletion is not pluggable. As of this writing (Django<=5)
180+
autocomplete is implemented for bash only and has no mechanism for passing the buck
181+
down to command implementations. The result of this in django-typer is that we wrap
182+
django's autocomplete and pass the buck to it instead of the other way around. This is
183+
fine but it will be awkward if two django command line apps with their own autocomplete
184+
infrastructure are used together. Django should be the central coordinating point for
185+
this. This is the reason for the pluggable --fallback awkwardness in shellcompletion.
186+
187+
4) Too much of the BaseCommand implementation is built assuming argparse. A more
188+
generalized abstraction of this interface is in order. Right now BaseCommand is doing
189+
double duty both as a base class and a protocol.
190+
191+
5) There is an awkwardness to how parse_args flattens all the arguments and options
192+
into a single dictionary. This means that when mapping a library like Typer onto the
193+
BaseCommand interface you cannot allow arguments at different levels
194+
(e.g. in initialize()) or group() functions above the command to have the same names as
195+
the command's options. You can work around this by using a different name for the
196+
option in the command and supplying the desired name in the annotation, but its an odd
197+
quirk imposed by the base class for users to be aware of.

doc/source/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ v2.1.0
66
======
77

88
* Implemented `Move tests into top level dir. <https://github.com/bckohan/django-typer/issues/87>`_
9+
* Implemented `Move core code out of __init__.py into management/__init__.py <https://github.com/bckohan/django-typer/issues/81>`_
910

1011

1112
v2.0.2

doc/source/reference.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,22 @@ django_typer
1414
------------
1515

1616
.. automodule:: django_typer
17+
18+
.. automodule:: django_typer.management
1719
:members:
1820
:exclude-members: Typer, CommandGroup, TyperCommand, Context, CommandNode
1921
:show-inheritance:
2022

21-
.. autoclass:: django_typer.Typer
23+
.. autoclass:: django_typer.management.Typer
2224
:members: callback, initialize, command, group, add_typer
2325

24-
.. autoclass:: django_typer.TyperCommand
26+
.. autoclass:: django_typer.management.TyperCommand
2527
:members: initialize, callback, command, group, echo, secho, print_help, get_subcommand
2628

27-
.. autoclass:: django_typer.CommandNode
29+
.. autoclass:: django_typer.management.CommandNode
2830
:members: name, click_command, context, children, get_command, print_help
2931

30-
.. autoclass:: django_typer.TyperCommandMeta
32+
.. autoclass:: django_typer.management.TyperCommandMeta
3133

3234
.. _types:
3335

tests/test_basics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
class BasicTests(TestCase):
1414
def test_common_options_function(self):
15-
from django_typer import _common_options
15+
from django_typer.management import _common_options
1616

1717
self.assertIsNone(_common_options())
1818

tests/test_interface.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def test_initialize_interface_matches(self):
144144
self.assertTrue(initialize is callback)
145145

146146
def test_typercommandmeta_interface_matches(self):
147-
from django_typer import TyperCommandMeta
147+
from django_typer.management import TyperCommandMeta
148148

149149
typer_command_params = set(get_named_arguments(TyperCommandMeta.__new__))
150150
typer_params = set(get_named_arguments(typer.Typer.__init__))
@@ -282,7 +282,7 @@ def test_cmd_getattr(self):
282282
pass
283283

284284
def test_proxied_property(self):
285-
from django_typer import BoundProxy
285+
from django_typer.management import BoundProxy
286286
from tests.apps.test_app.management.commands.basic import (
287287
Command as Basic,
288288
)
@@ -305,7 +305,7 @@ def sqrt(self):
305305
pass
306306

307307
def test_attribute_access_outside_of_definition(self):
308-
from django_typer import TyperCommand, TyperCommandMeta
308+
from django_typer.management import TyperCommand, TyperCommandMeta
309309
from tests.apps.test_app.management.commands.native import app
310310

311311
with self.assertRaises(AttributeError):

0 commit comments

Comments
 (0)