Weird Exception While Testing

Tracebacks are crucial part of a coding process. Even more so when writing tests. So when traceback gives you inaccurate information, it can really mess with you. Last week I spent way too long on an exception that should have been trivial. The reason? Incomplete traceback.

I wrote a test for email templates in test_email_templates.py with the following imports:

# -*- coding: utf-8 -*-
from django.test import TestCase
from django.template.loader import get_template, TemplateDoesNotExist
from django.utils.translations import override
from django.conf import settings
from django.contrib.sites.models import Site

After I wrote the test, I ran the test which resulted in a weird exception

$ ./manage.py test my_app.tests.test_email_templates
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/__init__.py", line 351, in execute_from_command_line
    utility.execute()
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/__init__.py", line 343, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/commands/test.py", line 30, in run_from_argv
    super(Command, self).run_from_argv(argv)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/commands/test.py", line 74, in execute
    super(Command, self).execute(*args, **options)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/raven/contrib/django/management/__init__.py", line 41, in new_execute
    return original_func(self, *args, **kwargs)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/core/management/commands/test.py", line 90, in handle
    failures = test_runner.run_tests(test_labels)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/test/runner.py", line 209, in run_tests
    suite = self.build_suite(test_labels, extra_tests)
  File "/Users/zanderle/.virtualenvs/env/lib/python3.4/site-packages/django/test/runner.py", line 121, in build_suite
    tests = self.test_loader.loadTestsFromName(label)
  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/unittest/loader.py", line 114, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'test_email_templates'

This got me scratching my head and I started looking for possible reasons. I got nowhere for 10 minutes. Eventually I noticed something by chance.

from django.utils.translations import override

There is no translations in django.utils. There is however, django.utils.translation. So simply changing it to

from django.utils.translation import override

Got everything working nicely. I later realized, that I could have figured this out by either running all the tests (or all the tests in the app), or trying to import this specific test. Both of which returns the accurate traceback.

In [1]: import my_app.tests.test_email_templates
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-f8f5ee3652d4> in <module>()
----> 1 import my_app.tests.test_email_templates

/Users/zanderle/Projects/dmt/datafy/my_app/tests/test_email_templates.py in <module>()
      2 from django.test import TestCase
      3 from django.template.loader import get_template, TemplateDoesNotExist
----> 4 from django.utils.translations import override
      5 from django.conf import settings
      6 from django.contrib.sites.models import Site

ImportError: No module named 'django.utils.translations'

When running all the tests in an app:

======================================================================
ERROR: my_app.tests.test_email_templates (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/unittest/case.py", line 58, in testPartExecutor
    yield
  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/unittest/case.py", line 577, in run
    testMethod()
  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/unittest/loader.py", line 32, in testFailure
    raise exception
ImportError: Failed to import test module: my_app.tests.test_email_templates
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/unittest/loader.py", line 312, in _find_tests
    module = self._get_module_from_name(name)
  File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/unittest/loader.py", line 290, in _get_module_from_name
    __import__(name)
  File "/Users/zanderle/Projects/dmt/datafy/my_app/tests/test_email_templates.py", line 4, in <module>
    from django.utils.translations import override
ImportError: No module named 'django.utils.translations'

I still haven’t figured out why this doesn’t show up when running a specific test. Useful to know though.