Opened 7 years ago
Closed 7 years ago
#29295 closed Bug (fixed)
BaseCommand.add_arguments crashes when using parser.add_subparsers().add_parser("subcommand")
Reported by: | Lutz Prechelt | Owned by: | Lutz Prechelt |
---|---|---|---|
Component: | Core (Management commands) | Version: | 1.11 |
Severity: | Normal | Keywords: | BaseCommand argparse subparser add_subparsers add_parser |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Background
Python's argparse allows to 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.)
Attachments (1)
Change History (6)
comment:1 by , 7 years ago
Summary: | BaseCommand.add_arguments does not allow parser.add_subparsers().add_parser("subcommand") → BaseCommand.add_arguments crashes when using parser.add_subparsers().add_parser("subcommand") |
---|---|
Triage Stage: | Unreviewed → Accepted |
by , 7 years ago
Attachment: | 29295.diff added |
---|
comment:2 by , 7 years ago
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.
comment:3 by , 7 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
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?