#33041 closed Bug (invalid)
call_command() returns different values for options than manage.py when nargs is specified.
| Reported by: | Kevin Follstad | Owned by: | nobody |
|---|---|---|---|
| Component: | Core (Management commands) | Version: | 3.1 |
| Severity: | Normal | Keywords: | call_command nargs |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Maybe I am not understanding something in the documentation, but this seems like a bug (tested on 3.1.7).
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.
Change History (3)
comment:1 by , 4 years ago
| Component: | Uncategorized → Core (Management commands) |
|---|
comment:2 by , 4 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
comment:3 by , 4 years ago
| Summary: | Call_command returns different values for options than manage.py (and itself) when nargs is specified → call_command() returns different values for options than manage.py when nargs is specified. |
|---|
Thanks for the ticket, however it's documented that named options are passed without "triggering the argument parser, which means you’ll need to pass the correct type".
💗