Динамически изменять ссылки из импорта в Python

Коротко:
Как импортировать модуль, если уже импортирован другой модуль с таким же именем? Старый модуль мне больше не нужен, но я не могу импортировать новый под другим именем. importlib.reload() не дает желаемого эффекта, и, видимо, не стоит связываться с sys.modules

Контекст:
Я автоматизирую рабочий процесс тестирования, пишу сценарий (A). Тестовый сценарий предоставляется и не может быть изменен.
Целью тестирования является класс в сценарии (B), различные версии которого находятся в подпапках. К сожалению, Script B и класс всегда имеют одно и то же имя, и я ничего не могу с этим поделать.

main_folder  
├──script_a.py  
├──test_script.py 
│ 
├──version_1
│    ├──script_b.py    
│
├──version_2  
│    ├──script_b.py 
│ 
├──version_3  
│    ├──script_b.py 

Тестовый скрипт импортирует объект и запускает на нем тесты.

# test_script
from script_b import my_class 

# creat instance of my_class
# and test it

script_a перебирает папки версий и запускает тестовый скрипт на script_b. В каждой итерации к пути импорта добавляется одна подпапка, поэтому тестовый скрипт найдет соответствующий файл script_b. Путь удаляется после итерации.
Если sys.modules уже содержит версию test_script,

# script_a
import sys
import os
import importlib

folders = ['version_1', 'version_2', 'version_3']
folders = [os.getcwd() + '/' + folder for folder in folders]

for folder in folders:
    sys.path.append(folder)


    if 'test_script' in sys.modules:
        importlib.reload(sys.modules['test_script'])
    else:
        importlib.import_module('test_script')

    sys.path.remove(folder)

Проблема:
Кажется, reload не влияет на script_b, который импортируется test_script. Поэтому, хотя я меняю путь импорта на разные подпапки, test_script всегда работает в версии 1. Как я могу заставить test_script использовать разные версии script_b, не изменяя сам test_script?

Дополнение. Хотя на первоначальный вопрос есть ответ, мне интересно, как это решение выглядит с точки зрения дизайна? Есть ли лучший/более элегантный способ автоматизировать этот процесс тестирования?
Из того, что я обнаружил, перезагрузка модулей не считается хорошей практикой.


person ColdBrew    schedule 14.11.2017    source источник


Ответы (1)


Разобрался, пока писал вопрос. Надеюсь, это поможет кому-то когда-нибудь

Даже если вы не можете изменить test_script (или script_b), есть обходной путь.
Поскольку оператор import ничего не делает, если соответствующий модуль уже импортирован, мы можем перезагрузить script_b из нужного нам пути непосредственно в script_a. Поскольку затем он заменяется новой версией в sys.modules, оператор импорта в test_script не вызовет проблем.

Обновленный код:

# script_a
import sys
import os
import importlib

folders = ['version_1', 'version_2', 'version_3']
folders = [os.getcwd() + '/' + folder for folder in folders]

for folder in folders:
    sys.path.append(folder)

    if 'test_script' in sys.modules:
        importlib.reload(sys.modules['script_b'])      # this line added
        importlib.reload(sys.modules['test_script'])
    else:
        importlib.import_module('test_script')

    sys.path.remove(folder)
person ColdBrew    schedule 14.11.2017