Python: динамически импортируемый модуль дает сбой при первом создании, а затем успешно - PullRequest
0 голосов
/ 18 января 2019

У меня есть шаблонизатор с именем Созерцай , в котором есть реализации для 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 секунду, если изначально не удалось импортировать модуль шаблона (см. Код онлайн-хранилища), но все равно иногда возникает такая же ошибка, когда шаблоны сначала создаются перед импортом. Любые решения?

1 Ответ

0 голосов
/ 18 января 2019

Правильно, если вы используете цикл while для обработки исключений, это будет одним из способов.

while True:
    try:
        #The module importing
        break
    except ModuleNotFoundError:
        print("NOPE! Module not found")

Если это работает для каких-то других, а не других «модульных» файлов, вероятным подозрением являются файлы шаблона сами файлы шаблона.

...