Python's [https://docs.python.org/3/library/argparse.html argparse] allows
to [https://docs.python.org/3/library/argparse.html?highlight=argparse
#sub-commands define subparsers].
The following works (but does nothing observable) in plain Python:
{{{
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
a_parser = subparsers.add_parser("A")
}}}
== Setup
The equivalent does ''not'' work in a `manage.py` custom command.
When I put this in file **`mycommand.py`**:
{{{
import django.core.management.base as djcmb
class Command(djcmb.BaseCommand):
def add_arguments(self, parser):
subparsers = parser.add_subparsers()
a_parser = subparsers.add_parser("A")
}}}
== Symptom
...and then run **`python manage.py mycommand A`**,
what I get is `TypeError: __init__() missing 1 required positional
argument: 'cmd'` with the following stacktrace:
{{{
File "manage.py", line 8, in <module>
execute_from_command_line(sys.argv)
File "C:\venv\rqc36\lib\site-
packages\django\core\management\__init__.py", line 364, in
execute_from_command_line
utility.execute()
File "C:\venv\rqc36\lib\site-
packages\django\core\management\__init__.py", line 356, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\venv\rqc36\lib\site-packages\django\core\management\base.py",
line 275, in run_from_argv
parser = self.create_parser(argv[0], argv[1])
File "C:\venv\rqc36\lib\site-packages\django\core\management\base.py",
line 249, in create_parser
self.add_arguments(parser)
File "C:\ws\bb\rqc\rqc\management\commands\mycommand.py", line 7, in
add_arguments
a_parser = subparsers.add_parser("A")
File "C:\sw\Python36-32\lib\argparse.py", line 1097, in add_parser
parser = self._parser_class(**kwargs)
}}}
== Diagnosis
The reason is that Django does not use a plain `ArgumentParser` but rather
its own `django.core.management.base.CommandParser`, the constructor of
which requires a positional argument:
{{{
def __init__(self, cmd, **kwargs): # ...
}}}
where `cmd` is supposed to contain the `mycommand.Command` object which is
then stored as `self.cmd` in the parser.
The following **kludge** helps the poor user trying to get subparsers to
work:
{{{
import argparse
import django.core.management.base as djcmb
class Command(djcmb.BaseCommand):
def add_arguments(self, parser):
subparsers = parser.add_subparsers()
subparsers._parser_class = argparse.ArgumentParser # circumvent
Django 1.11 bug
a_parser = subparsers.add_parser("A")
}}}
== Repair suggestions
**S1**: The most straightforward repair I see would be to make the
argument optional (`*argv`) and use a dummy object for `self.cmd` in case
of subparsers. `self.cmd` is used only three times. Is this good enough?
**S2**: Alternatively, one could simply document the problem and the
kludge. (BTW: The custom commands how-to should become more explicit
regarding the use of `argparse`; it is currently only hinted at, never
mentioned.)
--
Ticket URL: <https://code.djangoproject.com/ticket/29295>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* stage: Unreviewed => Accepted
Comment:
While investigating the issue, I wrote a patch that I think should solve
the issue. What remains is to add a test, probably in
`tests/user_commands`. What you like to try that?
--
Ticket URL: <https://code.djangoproject.com/ticket/29295#comment:1>
* Attachment "29295.diff" added.
Comment (by Lutz Prechelt):
Yes, will try.
I have started to work my way into Django development (the new-developer
docs appear to be very good), but have a lot of the way left to go. Will
take a while, but I'll get to it eventually.
--
Ticket URL: <https://code.djangoproject.com/ticket/29295#comment:2>
* status: new => assigned
* owner: nobody => Lutz Prechelt
--
Ticket URL: <https://code.djangoproject.com/ticket/29295#comment:3>
* has_patch: 0 => 1
* stage: Accepted => Ready for checkin
Comment:
[https://github.com/django/django/pull/9894 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/29295#comment:4>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"dd68b51e1da54267bde4799fa0d9fbd4290eb8b5" dd68b51e]:
{{{
#!CommitTicketReference repository=""
revision="dd68b51e1da54267bde4799fa0d9fbd4290eb8b5"
Fixed #29295 -- Fixed management command crash when using subparsers.
Thanks Tim Graham for the fix.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/29295#comment:5>