Should management command verbosity levels be labelled?

The default verbosity levels of Django management commands are magic numbers; should those values be mapped to an object?


Context:

Django’s management commands provide each command with an optional verbosity argument with allowed values ranging from 0 to 3.

Each number represents a level which is described in the help function for commands, but not in the command class themselves: it is up to the developer to determine which output belongs to which level.

I personally found it more descriptive to map the values to sensibly named constants—or even better, an Enum—to remove some of the guesswork of what each level represents.


Code:

The manage. py help command provides this explanation for the available verbosity levels:

-v, --verbosity {0,1,2,3}
    Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output

Which you could map to an enum like so:

from enum import IntEnum


class Verbosity(IntEnum):
    """Verbosity level corresponding to Django management command defaults."""

    MINIMAL_OUTPUT = 0
    NORMAL_OUTPUT = 1
    VERBOSE_OUTPUT = 2
    VERY_VERBOSE_OUTPUT = 3

What do you think?

NB. I expected there to already be a topic about this subject but could not find it. If this has already been discussed before, please feel free to share the relevant link.

3 Likes

<opinion>
As an addition or supplement to using the numbers, I guess I wouldn’t see an issue with that. (I can’t see me ever using them, but I acknowledge it can be considered a personal choice.)

I can’t see myself implementing them by name in the management commands that I create, nor would I envision myself implementing tests for them in my code, which means I’d be expecting Django to convert the names to numbers in the argument values passed to the handler.

As a replacement, I would be strongly against it, as it would create an uncommon convention for specifying levels.

In fact, if a change were to be made here, I’d prefer going in the other direction.

There are a number of linux commands that use repeated instances of -v, and/or patterns of -v, -vv, -vvv to identify the level of verbosity. (Some that I can think of right off-hand include tar, ssh, tcpdump, and pip.)

If any change were to be made, my preference would be to adhere more to the existing conventions rather that implementing something new.

Side note: POSIX doesn’t address this issue, merely to say that different levels of verbosity are program-specific - which also means that it’s valid to create a non-sequential set of verbosity levels. There’s nothing saying that the output of -vv or -v 2 must include the output of -v, although that does appear to be true for all examples I can think of.
</opinion>

I assumed the proposal only related to call_command() usage, not command-line usage, but that may have been a premature assumption!

1 Like

+1 for the simple fact that ruff complains about ‘magic’ numbers so in a custom management command having this available would be clearer in that code:
ie instead of

...
if verbosity >= 1:
...

having:

...
if verbosity >= Verbosity.NORMAL_OUTPUT:
...
2 Likes

+1 from me. I believe we will need an IntEnum to avoid breaking existing code. Let’s keep the names short: Verbosity.MINIMAL etc.

2 Likes

I assumed the proposal only related to call_command() usage, not command-line usage, but that may have been a premature assumption!

This assumption is correct; my recommendation is for Python code only.

I like Ken’s proposal as well, but that would be a separate discussion and lead to a possibly breaking change for existing management command calls.

Like so then?

from enum import IntEnum


class Verbosity(IntEnum):
    MINIMAL = 0
    NORMAL = 1
    VERBOSE = 2
    VERY_VERBOSE = 3
2 Likes

I created a GitHub ticket based off this idea:

2 Likes

The existence of such an Enum wouldn’t really help me implement logging, as I still need to reinvent all the other parts for useful logging. I always expect Django to actually do something useful with the -v flag by itself, as it provides the flag out of the box, but it doesn’t.

E.g. When using default Python logging in management commands and called libraries, the logger adheres to the settings in Django’s settings.LOGGING dict, and to me it seems intuitive that a management command called with -v 3 will switch (for the output of that command) the log level to logging.DEBUG.

Unfortunately the current implementation doesn’t do anything useful, depending solely on the command implementor who has to re-invent the wheel somehow. While a generic interface is available in the CLI (raising end-user expectations), this results in many different verbosity-handling implementations, or no implementation at all (most of the time). As an end-user, that annoys me to no end, and as a developer I always (ok, sometimes) need to think up some way to use this flag: there’s no obvious or preferred, documented approach. Over the years I might have created a dozen slightly different ways to handle this.

The fact that the numeric values don’t naturally map to Python’s logging log levels as they have opaque descriptions, doesn’t really help of course. All of this results in many ‘verbose-ignorant’ command implementations.

My basic idea would be to implement in Django something like:

  • Map -v values to Python log levels (e.g. 0 → logging.WARNING, 3 → logging.DEBUG).
  • Automatically switch log level of the root level to the given verbosity.
  • Promote use of the logging module in the management command documentation, and maybe some preferred way to combine it with Command.stdout.write().

Would this be any good? Other ideas and suggestions welcome of course.

These are interesting points that warrant their own thread, as this thread is not about logging.

Hi @Mah-Rye-Kuh , thanks for your reply. I guess you are correct, I’ll create a new thread. What triggered me to follow up here is probably the fact that you are interested to improve or simplify (and maybe standardize) how to use the existing -v flag in management commands, which is exactly what my post was about.

New thread in Implement default handling of --verbosity in management commands