У меня есть шаблонизатор с именем Созерцай , в котором есть реализации для php
, node/js
и python
.
Все работает нормально, за исключением того, что в последнее время реализация Python вызывает у меня некоторые проблемы. В частности, проблема возникает при первом анализе шаблона и создании кода Python шаблона, который затем динамически импортируется как модуль. Когда шаблон уже создан, все работает нормально, но когда шаблон должен быть проанализирован и сохранен на диске, а затем импортирован, возникает ошибка, например
ModuleNotFoundError: No module named 'blah blah'
( примечание эта ошибка кажется случайной, она не всегда уверена, что она будет возникать, много раз она работает, даже если шаблон создается непосредственно перед импортом, в других случаях происходит сбой, а затем, если выполняется снова с уже созданным шаблоном это удается)
Можно ли как-нибудь обойти эту проблему, возможно, добавить задержку между сохранением разобранного шаблона и последующим импортом в виде модуля или еще чем-нибудь?
Код для импорта модуля (проанализированный шаблон, который теперь является классом Python) приведен ниже:
def import_tpl( filename, classname, cacheDir, doReload=False ):
# http://www.php2python.com/wiki/function.import_tpl/
# http://docs.python.org/dev/3.0/whatsnew/3.0.html
# /2675979/dinamicheskoe-sozdanie-python-iz-strokovogo-imeni-klassa-v-dinamicheski-importirovannom-module
#_locals_ = {'Contemplate': Contemplate}
#_globals_ = {'Contemplate': Contemplate}
#if 'execfile' in globals():
# # Python 2.x
# execfile(filename, _globals_, _locals_)
# return _locals_[classname]
#else:
# # Python 3.x
# exec(read_file(filename), _globals_, _locals_)
# return _locals_[classname]
# http://docs.python.org/2/library/imp.html
# http://docs.python.org/2/library/functions.html#__import__
# http://docs.python.org/3/library/functions.html#__import__
# http://stackoverflow.com/questions/301134/dynamic-module-import-in-python
# http://stackoverflow.com/questions/11108628/python-dynamic-from-import
# also: http://code.activestate.com/recipes/473888-lazy-module-imports/
# using import instead of execfile, usually takes advantage of Python cached compiled code
global _G
getTplClass = None
# add the dynamic import path to sys
basename = os.path.basename(filename)
directory = os.path.dirname(filename)
os.sys.path.append(cacheDir)
os.sys.path.append(directory)
currentcwd = os.getcwd()
os.chdir(directory) # change working directory so we know import will work
if os.path.exists(filename):
modname = basename[:-3] # remove .py extension
mod = __import__(modname)
if doReload: reload(mod) # Might be out of date
# a trick in-order to pass the Contemplate super-class in a cross-module way
getTplClass = getattr( mod, '__getTplClass__' )
# restore current dir
os.chdir(currentcwd)
# remove the dynamic import path from sys
del os.sys.path[-1]
del os.sys.path[-1]
# return the tplClass if found
if getTplClass: return getTplClass(Contemplate)
return None
Примечание движок создает файл __init__.py
в cacheDir
, если его там еще нет.
При необходимости я могу изменить функцию import_tpl
на что-то другое, я не против.
Python протестирован python 3.6
на windows
, но я не думаю, что это проблема для конкретной платформы.
Чтобы проверить проблему, вы можете загрузить репозиторий github
(ссылка выше) и запустить тест /tests/test.py
после очистки всех кэшированных шаблонов из папки /tests/_tplcache/
.
UPDATE:
Я думаю о добавлении цикла while
с некоторым счетчиком в import_tpl
, который перехватывает возникшую ошибку, если таковая имеется, и повторяет указанное количество раз, пока не удастся импортировать модуль. Но мне также интересно, если это хорошее решение или есть что-то еще, что я здесь упускаю ..
ОБНОВЛЕНИЕ (20/02/2019):
Добавлен цикл для повторения указанного количества раз плюс небольшая задержка в 1 секунду, если изначально не удалось импортировать модуль шаблона (см. Код онлайн-хранилища), но все равно иногда возникает такая же ошибка, когда шаблоны сначала создаются перед импортом. Любые решения?