Модуль Python в пути: ошибка ImportError в шаблоне mako - PullRequest
2 голосов
/ 25 июля 2011

Существует ошибка ImportError, которая может свести меня с ума.Ситуация выглядит следующим образом:

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

Код (без каталога тестов, который я не решаюсь зафиксировать до того, как проблема будет решена) находится здесь: https://github.com/Boldewyn/website/.

Когда явызов python -m website.__main__ build, основная подпрограмма создает из некоторых входных статических файлов HTML, используя шаблоны в website/_templates.Это прекрасно работает в любом каталоге.

Тем не менее, в tests/testWebsite.py у меня есть модульный тест, который должен запускать тоже самое.Но там шаблоны Mako вызывают ошибки импорта для файлов, которые отлично импортируются в другом случае.

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

Запуск теста затем приводит к:

$ 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

Теперь забавная часть, что я могу напечатать sys.path прямо из шаблона:

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

И я могу подтвердить там, что website - это в пути.Кроме того, импорт хорошо работает в любом другом сценарии развертывания.

Импорт website или website._webtools также работает хорошо.Только часть website._webtools.templatedefs идет не так.

У кого-нибудь есть идеи, где я могу найти признаки того, что может пойти не так?

Тестовый код довольно прост:

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)

Редактировать: Еще одна диагностика: я позволил mako скомпилировать шаблон и выполнить полученный файл Python отдельно.Работает как шарм.Я также уменьшил templatedefs.py до минимума (только defs возвращает пустые строки), чтобы в этом файле можно было исключить ImportErrors (или другие странности).Ubuntu 11.04, Python 2.7, Mako 0.3.6.

1 Ответ

3 голосов
/ 06 августа 2011

Это действительно сводит с ума. Однако вот некоторые вещи:

  1. ./nosetests: это работает, и все 9 тестов проходят

  2. 'templatedefs' - единственный ключ, отсутствующий в '_webtools.__dict__' при добавлении 'from website import _webtools' в шаблон mako и сравнении 'nosetests' с 'python -m unittest tests.testWebsite': другие детали уже были импортированы ранее

  3. sys.path содержит '' (относительный путь) в случае 'python -m unittest tests.testWebsite', но не в случае 'nosetests', где sys.path содержит только абсолютные пути. Это приводит к различным значениям 'website._webtools.__file__': одно относительное ['website/_webtools'], другое абсолютное ['/home/username/tmp/website/_webtools']. Поскольку вы делаете os.chdir, относительные пути больше не работают.

SO: Если вы хотите использовать чистый юнит-тест, вы можете добавить 'import website._webtools.templatedefs' в начале вашего тестового файла. Это гарантирует, что у вас есть шаблоны, импортированные при запуске os.chdir. И я бы предложил использовать нос. Надеюсь, это поможет.

...