#python #ansible #pytest
#python #ansible #pytest
Вопрос:
У нас есть тестовая платформа, которая немного расширяет pytest и оборачивает его большим количеством Ansible, чтобы запускать приемочные тесты конфигурации системы, чтобы убедиться, что наша инфраструктура установлена и настроена правильно и, похоже, работает нормально. Это делается с помощью Ansible для упаковки тестов, отправки их на удаленный хост, затем распаковки их в virtualenv для запуска тестов. Пока что тесты большинства пользователей включают выполнение команд на удаленном хосте для проверки их работы.
Часть того, что я пытаюсь проверить, установлены ли и работают ли некоторые модули Python, и если они установлены, используйте их в дальнейших тестах. Но я несколько загнан в тупик из-за того, что virtualenv (совершенно справедливо) скрывает все установленные в системе модули Python.
Пока что моя стратегия заключается в запуске subprocess
командной оболочки / небольшого скрипта, который отключает все переменные среды, связанные с virtualenv, а затем запускает короткий скрипт Python, используя системный python, который выбирает его sys.path
и сбрасывает в стандартный вывод.
Но тогда я не уверен насчет следующего шага. Как правильно обращаться с sys.path
внутри теста или приспособления? Восстановит ли pytest его, как только устройство больше не понадобится? Что pytest делает с модулями, которые импортирует тест? Удаляет ли это их из sys.modules после завершения теста?
Ответ №1:
Ну, я не получил ответа, поэтому я придумал это приспособление для установки conftest.py
:
@pytest.fixture(scope="module")
def need_system_libraries():
pycmd = 'unset VIRTUAL_ENV PYTHONPATH; exec {pyexec} -c '
'"import sys, pickle; sys.stdout.write(pickle.dumps(sys.path, 0))"'
pycmd = pycmd.format(pyexec='/usr/bin/python3.7')
_, stdout, _ = testlib.execute(pycmd)
system_path = pickle.loads(stdout)
# Prune any paths from the system_path that already exist in sys.path or
# are relative (not absolute) paths.
newsyspaths = frozenset(system_path) - frozenset(sys.path)
newsyspaths = frozenset(path for path in newsyspaths
if os.path.isabs(path))
# A set isn't ordered. Put difference back in the same order as the
# elements appeared in system_path. (Not needed in Python >= 3.6).
newsyspaths = [path for path in system_path if x in newsyspaths]
# Save a copy of the path so we can restore it.
saved_syspath = sys.path.copy()
sys.path.extend(newsyspaths)
# This fixture modifies the environment itself, and so doesn't need to
# return a value.
yield None
# The yield will come back when this fixture is no longer needed, so
# restore sys.path back to its original value. Do this by copying elements
# back into original sys.path in case the identity of sys.path is important
# somewhere deep in the bowels of Python.
sys.path[:] = saved_syspath