Question

There is an ImportError that has the potential to drive me mad. The situation looks like this:

tests/
    testWebsite.py
website/
    __init__.py
    __main__.py
    _webtools/
        __init__.py
        templatedefs.py
        ...
    _templates/
        base.mako
        article.mako
        ...

The code (sans the tests directory, which I hesitate to commit, before the problem is solved) is online here: https://github.com/Boldewyn/website/.

When I call python -m website.__main__ build, the main routine creates from some input static HTML files using the templates under website/_templates. This works just fine in any given directory.

However, in the tests/testWebsite.py I have a unit test, that should run the same thing, too. But there the Mako templates raise import errors for files, that are imported fine in the other case.

$ head -n 5 website/_templates/article.mako
# -*- coding: utf-8 -*-
<%!
from website._webtools.templatedefs import strip_tags
%>
<%inherit file="base.mako" />

Running the test then yields:

$ python -m unittest tests.testWebsite
...
ERROR: test_initial_build (tests.testWebsite.BuildTestCase)
Check, if building directly after bootstrap works
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/testWebsite.py", line 99, in test_initial_build
  File "website/_webtools/build.py", line 89, in build
    article.save(articles=articles)
  File "website/_webtools/articles.py", line 514, in save
    template_engine.render_article(self, **ctx)
  File "website/_webtools/templates.py", line 52, in render_article
    r.render_article(article, **ctx)
  File "website/_webtools/templates.py", line 277, in render_article
    tpl = self.lookup.get_template(filename)
  File "/usr/lib/python2.7/dist-packages/mako/lookup.py", line 217, in get_template
    return self._load(srcfile, uri)
  File "/usr/lib/python2.7/dist-packages/mako/lookup.py", line 277, in _load
    **self.template_args)
  File "/usr/lib/python2.7/dist-packages/mako/template.py", line 205, in __init__
    module = self._compile_from_file(path, filename)
  File "/usr/lib/python2.7/dist-packages/mako/template.py", line 249, in _compile_from_file
    filename)
  File "/usr/lib/python2.7/dist-packages/mako/template.py", line 470, in _compile_text
    exec code in module.__dict__, module.__dict__
  File "_templates_article_mako", line 16, in <module>
ImportError: No module named templatedefs

Now, the funny part is, that I can print sys.path directly from the template:

<%!
import sys
print sys.path
from website._webtools.templatedefs import strip_tags
%>

And I can confirm there, that website is in the path. Also, the import does work well in every other deployment scenario.

Importing website or website._webtools also works well. Only the website._webtools.templatedefs part goes wrong.

Has anyone an idea, where I could look to find signs of what might go wrong?

The test code is quite straight-forward:

class BuildTestCase(unittest.TestCase):

    def setUp(self):
        self.tmpdir = tempfile.mkdtemp()
        self.cwd = os.getcwd()
        os.chdir(self.tmpdir)
        bootstrap(self.tmpdir, { # this initiates a new project
          "URL": "localhost",
          "TITLE": "Example",
          "DEFAULTS": {
              "AUTHOR": "John Doe",
          }
        })

    def test_initial_build(self):
        """Check, if building directly after bootstrap works"""
        build()

    def tearDown(self):
        os.chdir(self.cwd)
        shutil.rmtree(self.tmpdir)

Edit: One more diagnostic: I let mako compile the template and executed the resulting Python file stand-alone. Works like a charm. I also reduced templatedefs.py to the bare minimum (only defs returning empty strings), so that I can exclude ImportErrors (or other weirdness) in that file as well.

System info: Ubuntu 11.04, Python 2.7, Mako 0.3.6.

Was it helpful?

Solution

This indeed drives one mad. However here are some things:

  1. ./nosetests: this works and all 9 tests pass

  2. 'templatedefs' is the only key missing in '_webtools.__dict__' when you add an 'from website import _webtools' to your mako template and compare 'nosetests' to 'python -m unittest tests.testWebsite': the other parts were already imported earlier

  3. sys.path contains '' (a relative path) in the 'python -m unittest tests.testWebsite' case, but not in the 'nosetests' case, where sys.path contains only absolute paths. This results in different values for 'website._webtools.__file__': one is relative ['website/_webtools'], the other is absolute ['/home/username/tmp/website/_webtools']. Since you make a os.chdir, the relative paths don't work any more.

SO: If you want to use pure unittest, you can add 'import website._webtools.templatedefs' at the beginning of your test file. This ensures that you have templatedefs imported when you run os.chdir. And I would suggest to use nose. Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top