A constant papercut for me is when I mistype some class string, and end up with an ImportError
. Very rarely is the stack trace good at pointing out the sourcing of the string it just tried to import.
This patch shows some ad-hoc fixes for this, but I’m wondering if there’s a smarter strategy here.
I’ve generally found that “configuration-loading”-related errors for Django have always been a bit miserable to debug because so much of it is lazy loading. A URL Conf misconfiguration will show up inside of the custom error handlers check! The stack trace is never pointing at the configuration, and it’s not clear to me if there’s something doable there.
the stacktrace when I have a mistaken ROOT_URLCONF
:
Traceback (most recent call last):
File "/Users/rtpg/proj/django/django/core/checks/urls.py", line 136, in check_custom_error_handlers
handler = resolver.resolve_error_handler(status_code)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/urls/resolvers.py", line 743, in resolve_error_handler
callback = getattr(self.urlconf_module, "handler%s" % view_type, None)
^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/utils/functional.py", line 47, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/urls/resolvers.py", line 711, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/.local/share/uv/python/cpython-3.12.6-macos-aarch64-none/lib/python3.12/importlib/__init__.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1324, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'foo'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/rtpg/proj/saasfarm/backend/manage.py", line 22, in <module>
main()
File "/Users/rtpg/proj/saasfarm/backend/manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/Users/rtpg/proj/django/django/core/management/__init__.py", line 442, in execute_from_command_line
utility.execute()
File "/Users/rtpg/proj/django/django/core/management/__init__.py", line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/rtpg/proj/django/django/core/management/base.py", line 413, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/rtpg/proj/django/django/core/management/base.py", line 454, in execute
self.check()
File "/Users/rtpg/proj/django/django/core/management/base.py", line 486, in check
all_issues = checks.run_checks(
^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/core/checks/registry.py", line 89, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/core/checks/urls.py", line 138, in check_custom_error_handlers
path = getattr(resolver.urlconf_module, "handler%s" % status_code)
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/utils/functional.py", line 47, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/proj/django/django/urls/resolvers.py", line 711, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/rtpg/.local/share/uv/python/cpython-3.12.6-macos-aarch64-none/lib/python3.12/importlib/__init__.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1324, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'foo'
The “infinite CPU cycles” solution would involve adding provenance annotations to settings attributes through some proxy object… but that’s a lot of CPU churn for when I mistype the settings.
Would it make sense to just add an explicit check that tries to do all the relevant imports for common settings so we can provide a more straightforward error message? Or is this a non-issue in people’s eyes?