Untangled Development

How to have Python show warnings when running Django

Stray animals warning sign

Image credit: Bahnfrend, CC BY-SA 4.0, via Wikimedia Commons

Recently I was listening to prolific author Nick Janetakis on the Django Chat podcast. Episode title Being a Productive Developer.

At one point, they discussed deprecation warnings.

Nick:

[..] you mentioned those deprecation warnings with runserver. I feel like I’m missing out a lot. Like if I’m using gunicorn in development, is there any way that I can get like a gunicorn hook to get that?

At that point I was wondering: I don’t get these warnings. And I use runserver not gunicorn. Hmm.

Carlton replied:

No, it’s not gunicorn. It’s Python. So you run Python with the W flag, the capital W flag, which is for warnings. And then you run it with all warnings. And then you get deprecation warnings, which are noisy by default. But also pending deprecation warnings. So the ones that will be removed too. You get those to show up in your console or in your logs. And then you can you can fix.

I tampered with the transcript text to make this easier to read. Full transcript here.

Python -W and Django

The -W flag, or “arg”, is documented here. Please take a look at those and the options available for the -W flag.

As Carlton described in the chat above -Wd would make Python show all warnings. Example usage with manage.py check:

$ python -Wd manage.py check
/path/to/.pyenv/versions/phcommt310/lib/python3.10/site-packages/django/conf/__init__.py:240: RemovedInDjango50Warning: The USE_L10N setting is deprecated. Starting with Django 5.0, localized formatting of data will always be enabled. For example Django will display numbers and dates using the format of the current locale.
  warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
System check identified no issues (0 silenced).

Whereas if you want to display all warnings other than deprecation warnings you can:

$ python -W ignore::DeprecationWarning manage.py check
System check identified no issues (0 silenced).

An interesting aspect of this is that warnings are emitted also when running tests and runserver. For instance, this is the output when running tests without the -W flag:

$ python manage.py test
Found 587 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
----------------------------------------------------------------------
Ran 587 tests in 10.098s

OK
Destroying test database for alias 'default'...

However I see helpful warnings when running the same command with the -W flag on:

$ python -Wd manage.py test
/path/to/.pyenv/versions/phcommt310/lib/python3.10/site-packages/django/conf/__init__.py:240: RemovedInDjango50Warning: The USE_L10N setting is deprecated. Starting with Django 5.0, localized formatting of data will always be enabled. For example Django will display numbers and dates using the format of the current locale.
  warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
/path/to/.pyenv/versions/phcommt310/lib/python3.10/site-packages/model_bakery/timezone.py:11: RemovedInDjango50Warning: The django.utils.timezone.utc alias is deprecated. Please update your code to use datetime.timezone.utc instead.
  from django.utils.timezone import now, utc
Found 587 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
................................................................................................................................................................................../path/to/.pyenv/versions/3.10.9/lib/python3.10/unittest/suite.py:107: ResourceWarning: unclosed file <_io.BufferedReader name='mainsite/tests/csv/sample.csv'>
  for index, test in enumerate(self):
ResourceWarning: Enable tracemalloc to get the object allocation traceback
.........................................................................................................................................................................................................................................................................................................................................................................................................................
----------------------------------------------------------------------
Ran 587 tests in 11.463s

OK
Destroying test database for alias 'default'...

I can see another two warnings that I did not see earlier.

One of the warnings is in “my project’s code”, mainsite app. While the other is a deprecation warning in the model_bakery third-party library. Nice!

I guess it’s time to “get back” to work and fix those newly-discovered warnings. Let me share a link to this before I get back to coding…

Another way: Python Development Mode

Adam Johnson pointed me in the Python Development Mode direction, thanks Adam! This is available as from Python version 3.7:

The Python Development Mode introduces additional runtime checks that are too expensive to be enabled by default. It should not be more verbose than the default if the code is correct; new warnings are only emitted when an issue is detected.

While it does offer more than emitting warnings, for the scope of this post, it can be enabled by passing -X dev. For example:

$ python -X dev manage.py test

This, in terms of warnings, emits the same warnings as when I ran:

$ python -Wd manage.py test

I will stick to Development Mode going forward. This is because of the ability to have it enabled via environment variable. I.e. by simply setting PYTHONDEVMODE to 1. No need to pass additional flags to any of the python manage.py commands!

You can set this in your .env depending on how you manage the environment variables for your Django project. But make sure to have PYTHONDEVMODE unset or set to 0 in production!

Upgrading Django

I usually look for deprecation warnings when I see a newer Django version being prepared for release.

Do you intend to upgrade a project’s code to the next Django version? A useful package to help upgrading your codebase is django-upgrade. Make sure you check that out.

Comments !