#29295: BaseCommand.add_arguments does not allow
parser.add_subparsers().add_parser("subcommand")
-------------------------------------+-------------------------------------
               Reporter:  Lutz       |          Owner:  nobody
  Prechelt                           |
                   Type:  Bug        |         Status:  new
              Component:  Core       |        Version:  1.11
  (Management commands)              |       Keywords:  BaseCommand
               Severity:  Normal     |  argparse subparser add_subparsers
           Triage Stage:             |  add_parser
  Unreviewed                         |      Has patch:  0
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 == Background

 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.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.cf6f2493e64fc81ff1935538d090b7f8%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to