Код: Выделить всё
import shutil
import tempfile
from pathlib import Path
from contextlib import contextmanager
@contextmanager
def on_exit(directory: Path):
backup = Path(tempfile.mkdtemp(prefix="backup_")) / directory.name
shutil.copytree(directory, backup, symlinks=True)
try:
yield
finally:
shutil.rmtree(directory)
shutil.copytree(backup, directory, symlinks=True)
shutil.rmtree(backup)
Код: Выделить всё
from pathlib import Path
from src.utils import rollback
def get_repo_root() -> Path:
current_dir = Path(__file__).resolve()
while current_dir != current_dir.parent:
if (current_dir / ".git").exists():
return current_dir
current_dir = current_dir.parent
raise RuntimeError("No repository root found.")
def test_rollback_on_exit():
with rollback.on_exit(get_repo_root()):
...
- Каталог — это корневой каталог моего проекта, и я запускаю pytest из этого каталога.
- Тест пройден, но после выполнения мой терминал оказывается в несогласованном состоянии. Например, после запуска теста я вижу такое поведение:
Код: Выделить всё
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> echo $PWD
/home/user/projects/dummy
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> echo $VIRTUAL_ENV
/home/user/.cache/pypoetry/virtualenvs/dummy-83ZLFGNe-py3.12
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> ls -la | wc -l
17
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> pytest tests/test_rollback.py
============================================= test session starts ==============================================
platform linux -- Python 3.12.3, pytest-7.2.1, pluggy-1.5.0
rootdir: /home/user/projects/dummy
plugins: cov-6.0.0, asyncio-0.21.1, typeguard-4.4.1, hypothesis-6.119.3
asyncio: mode=Mode.STRICT
collected 1 item
tests/test_rollback.py . [100%]
=============================================== warnings summary ===============================================
tests/test_rollback.py: 20 warnings
/home/user/.cache/pypoetry/virtualenvs/dummy-83ZLFGNe-py3.12/lib/python3.12/site-packages/typer/core.py:300: DeprecationWarning: 'autocompletion' is renamed to 'shell_complete'. The old name is deprecated and will be removed in Click 8.1. See the docs about 'Parameter' for information about new behavior.
_typer_param_setup_autocompletion_compat(self, autocompletion=autocompletion)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================================== 1 passed, 20 warnings in 0.74s ========================================
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> echo $PWD
/home/user/projects/dummy
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> echo $VIRTUAL_ENV
/home/user/.cache/pypoetry/virtualenvs/dummy-83ZLFGNe-py3.12
(dummy-py3.12) user@laptop ~/p/dummy> ls -la | wc -l
1
(dummy-py3.12) user@laptop ~/p/dummy> cd .
(dummy-py3.12) user@laptop ~/p/dummy (feat/rollback)> ls -la | wc -l
17
Дополнительные наблюдения
- Эта проблема затрагивает не только pytest. Например, запуск source ~/.config/fish/config.fish после теста приводит к аналогичным ошибкам ().
Код: Выделить всё
getcwd: cannot access parent directories
- и $VIRTUAL_ENV остаются неизменными до и после теста, что позволяет предположить, что проблема не в самой виртуальной среде.
Код: Выделить всё
$PWD
Я попробовал изменить контекстный менеджер, чтобы изменить рабочий каталог перед удалением/восстановлением исходного каталога:
Код: Выделить всё
@contextmanager
def change_dir(target_path):
original_path = Path.cwd()
try:
os.chdir(target_path)
yield
finally:
os.chdir(original_path)
@contextmanager
def on_exit(directory: Path):
backup = Path(tempfile.mkdtemp(prefix="backup_")) / directory.name
shutil.copytree(directory, backup, symlinks=True)
try:
yield
finally:
with change_dir("/"):
shutil.rmtree(directory)
shutil.copytree(backup, directory, symlinks=True)
shutil.rmtree(backup)
Код: Выделить всё
cd .
Вопросы:
[*]Почему это происходит? Связано ли это с оболочкой, pytest или виртуальной средой?
Как я могу изменить свой контекстный менеджер или настройки тестирования, чтобы обеспечить полное восстановление состояния терминала после теста?
Подробнее здесь: https://stackoverflow.com/questions/792 ... l-in-erron