When nargs is specified for an option, according to the argparse
documentation, the parsed option should always be a list containing the
option's values. However that is not the case if options are specified as
kw="the-kw-option" when passed to call_command. For example:
''main/test/management/commands/commandbug.py:''
{{{
from django.core.management.base import BaseCommand
from django.core.management import call_command
# Broken: kw is not a list
def call_commandbug1():
call_command("commandbug", "the-positional-arg", kw="the-kw-arg")
# Works: kw is a list
def call_commandbug2():
call_command("commandbug", "the-positional-arg", "--kw=the-kw-arg")
class Command(BaseCommand):
help = "Minimal call_command bug demo"
def add_arguments(self, parser):
parser.add_argument(
"positional", nargs=1, type=str, help="Positional arg"
)
parser.add_argument(
"--kw",
nargs=1,
type=str,
help="Keyword arg",
)
super().add_arguments(parser)
def handle(self, *args, **options):
print(options)
}}}
When run from call_command1 the value of kw is not a list:
{{{
$> ./manage.py shell
Python 3.9.6 (default, Jun 30 2021, 10:22:16)
In [1]: from main.test.management.commands.commandbug import
call_commandbug1, call_commandbug2
In [2]: call_commandbug1()
{'verbosity': 1, 'settings': None, 'pythonpath': None, 'traceback': False,
'no_color': False, 'force_color': False, 'skip_checks': True,
'positional': ['the-positional-arg'], 'kw': 'the-kw-arg'}
}}}
When run from call_command2, the value is kw is a list matching argparse:
{{{
In [3]: call_commandbug2()
{'verbosity': 1, 'settings': None, 'pythonpath': None, 'traceback': False,
'no_color': False, 'force_color': False, 'skip_checks': True,
'positional': ['the-positional-arg'], 'kw': ['the-kw-arg']}
}}}
When run via manage.py it also works as expected / per argparse:
{{{
$> ./manage.py commandbug "the-positional-arg" --kw "the-kw-arg"
{'verbosity': 1, 'settings': None, 'pythonpath': None, 'traceback': False,
'no_color': False, 'force_color': False, 'skip_checks': False,
'positional': ['the-positional-arg'], 'kw': ['the-kw-arg']}
}}}
Hopefully this makes sense, and is a useful observation.
On an unrelated note, thanks for all you do! Django has been a life
changing framework for me.
--
Ticket URL: <https://code.djangoproject.com/ticket/33041>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* component: Uncategorized => Core (Management commands)
--
Ticket URL: <https://code.djangoproject.com/ticket/33041#comment:1>
* status: new => closed
* resolution: => invalid
Comment:
Thanks for the ticket, however it's
[https://docs.djangoproject.com/en/3.2/ref/django-admin/#running-
management-commands-from-your-code documented] that named options are
passed without ''"triggering the argument parser, which means you’ll need
to pass the correct type"''.
> On an unrelated note, thanks for all you do! Django has been a life
changing framework for me.
💗
--
Ticket URL: <https://code.djangoproject.com/ticket/33041#comment:2>
--
Ticket URL: <https://code.djangoproject.com/ticket/33041#comment:3>