[Django] #33205: call_command fails when required mutually exclusive group arguments use the same `dest`

4 views
Skip to first unread message

Django

unread,
Oct 16, 2021, 10:15:12 AM10/16/21
to django-...@googlegroups.com
#33205: call_command fails when required mutually exclusive group arguments use the
same `dest`
-----------------------------------------+------------------------
Reporter: Peter Law | Owner: nobody
Type: Uncategorized | Status: new
Component: Uncategorized | Version: 3.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-----------------------------------------+------------------------
I have a command which accepts two different ways to specify a time --
either as a timestamp or as a duration in the future:
{{{
pause (--for duration | --until time)
}}}

{{{#!python
class Command(BaseCommand):
def add_arguments(self, parser) -> None:
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--for', dest='until', action='store',
type=parse_duration_to_time)
group.add_argument('--until', action='store', type=parse_time)

def handle(self, until: datetime, **_):
pass
}}}


This works fine on the command line, however there doesn't seem to be a
way to make this work through `call_command`. Specifically there are two
sides to the failure:
- while I can provide an `until` value (as a string, which is processed by
`parse_time`) there is no mechanism to pass a `for` value if that's how I
want to spell the input
- the `for` value is always required and attempts to parse the (string)
`until` value passed, which then errors since the input formats are very
different

--
Ticket URL: <https://code.djangoproject.com/ticket/33205>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Oct 18, 2021, 5:44:51 AM10/18/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------

Reporter: Peter Law | Owner: nobody
Type: Bug | Status: new
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* cc: Hasan Ramezani (added)
* type: Uncategorized => Bug
* component: Uncategorized => Core (Management commands)
* stage: Unreviewed => Accepted


Comment:

Thanks for the report. The following calls work as expected for me :
{{{#!python
management.call_command('pause', '--until=1')
management.call_command('pause', '--until', '1')
management.call_command('pause', '--for=1')
management.call_command('pause', '--for', '1')
}}}
however I confirmed an issue when passing arguments in keyword arguments:
{{{
management.call_command('pause', until='1')
management.call_command('pause', **{'for': '1'}) # Using
"call_command('pause', for='1')" raises SyntaxError
}}}

This is caused by using `dest` for mapping `**options` to arguments, see
[https://github.com/django/django/blob/e2f778d57947d168a875159e6df075255eea4bbc/django/core/management/__init__.py#L117-L121
call_command()].

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:1>

Django

unread,
Oct 18, 2021, 10:16:23 AM10/18/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------

Reporter: Peter Law | Owner: nobody
Type: Bug | Status: new
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Hasan Ramezani):

I can create a patch to fix the two above-mentioned issues but using the
command with both options together:

`management.call_command('pause', **{'for': '1', 'util': '1'})`

won't raise an error because both options use the same `dest`.

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:2>

Django

unread,
Oct 18, 2021, 3:09:05 PM10/18/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------

Reporter: Peter Law | Owner: nobody
Type: Bug | Status: new
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Peter Law):

Ah, interesting, I wasn't aware that those other spellings worked! I'd be
happy to switch to using those spellings instead (I've confirmed they work
for my original case).

Perhaps just documenting this limitation (and the fact that those
spellings work as alternatives) and/or improving the related error
messages could be a way to go here?

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:3>

Django

unread,
Oct 19, 2021, 12:08:19 AM10/19/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------

Reporter: Peter Law | Owner: nobody
Type: Bug | Status: new
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak):

Replying to [comment:2 Hasan Ramezani]:
> I don't know do we have to support passing both dest and arg name as
keyword arguments? in the example of this ticket, if we call
`management.call_command('pause', until='1')`, it should be considered as
`until` arg or `for` (because `dest` of `for` is `until` as well)

We should support option names as
[https://docs.djangoproject.com/en/3.2/ref/django-
admin/#django.core.management.call_command documented]:
> `** options`
> named options accepted on the command-line.
so
* `management.call_command('pause', until='1')` should work the same as
calling `pause --until 1`
* `management.call_command('pause', **{'for': '1'})` should work the same
as calling `pause --for 1`
* `management.call_command('pause', **{'for': '1', 'until': '1'})` should
work the same as calling `pause --for 1 --until 1` and raise an exception

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:4>

Django

unread,
Oct 19, 2021, 10:34:28 AM10/19/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------

Reporter: Peter Law | Owner: nobody
Type: Bug | Status: new
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Hasan Ramezani):

Replying to [comment:4 Mariusz Felisiak]:

I am not sure about your second example:

> * `management.call_command('pause', **{'for': '1'})` should work the
same as calling `pause --for 1`

Based on the documentation, it seems we have to pass `dest` as keyword
argument name when we define `dest` for arguments.


>Some command options have different names when using call_command()
instead of django-admin or manage.py. For example, django-admin
createsuperuser --no-input translates to call_command('createsuperuser',
interactive=False). To find what keyword argument name to use for
call_command(), check the command’s source code for the dest argument
passed to parser.add_argument().


Also, when Django
[https://github.com/django/django/blob/e2f778d57947d168a875159e6df075255eea4bbc/django/core/management/__init__.py#L149
adds required arguments in call command], it search for `dest` in options.

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:5>

Django

unread,
Oct 19, 2021, 2:23:58 PM10/19/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------

Reporter: Peter Law | Owner: nobody
Type: Bug | Status: new
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak):

You're right, sorry, I missed ''"... check the command’s source code for
the **dest** argument passed to parser.add_argument()."''. In that case I
would raise an error that passing `dest` with multiple arguments via
`**options` is not supported.

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:6>

Django

unread,
Oct 20, 2021, 3:26:26 AM10/20/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------
Reporter: Peter Law | Owner: Hasan
| Ramezani
Type: Bug | Status: assigned

Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Hasan Ramezani):

* owner: nobody => Hasan Ramezani
* status: new => assigned


--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:7>

Django

unread,
Oct 22, 2021, 11:14:12 AM10/22/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------
Reporter: Peter Law | Owner: Hasan
| Ramezani
Type: Bug | Status: assigned
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Hasan Ramezani):

* has_patch: 0 => 1


Comment:

[https://github.com/django/django/pull/15018 PR]

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:8>

Django

unread,
Oct 25, 2021, 1:37:47 AM10/25/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------
Reporter: Peter Law | Owner: Hasan
| Ramezani
Type: Bug | Status: assigned
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* stage: Accepted => Ready for checkin


--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:9>

Django

unread,
Oct 25, 2021, 4:09:07 AM10/25/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------
Reporter: Peter Law | Owner: Hasan
| Ramezani
Type: Bug | Status: closed

Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution: fixed

Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak <felisiak.mariusz@…>):

* status: assigned => closed
* resolution: => fixed


Comment:

In [changeset:"c1e4111c74ee9d9f48cbee5a5b7c40289203c93d" c1e4111c]:
{{{
#!CommitTicketReference repository=""
revision="c1e4111c74ee9d9f48cbee5a5b7c40289203c93d"
Fixed #33205 -- Made call_command() raise TypeError when dest with
multiple arguments is passed.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:10>

Django

unread,
Oct 25, 2021, 4:09:50 AM10/25/21
to django-...@googlegroups.com
#33205: call_command() fails when required mutually exclusive arguments use the
same `dest`.
-------------------------------------+-------------------------------------
Reporter: Peter Law | Owner: Hasan
| Ramezani
Type: Bug | Status: closed
Component: Core (Management | Version: 3.2
commands) |
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Mariusz Felisiak <felisiak.mariusz@…>):

In [changeset:"c9ebe4ca4e3f5d5d76bfbdae489e3f44e32416e5" c9ebe4ca]:
{{{
#!CommitTicketReference repository=""
revision="c9ebe4ca4e3f5d5d76bfbdae489e3f44e32416e5"
[4.0.x] Fixed #33205 -- Made call_command() raise TypeError when dest with
multiple arguments is passed.

Backport of c1e4111c74ee9d9f48cbee5a5b7c40289203c93d from main
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/33205#comment:11>

Reply all
Reply to author
Forward
0 new messages