Last active
October 19, 2022 01:47
-
-
Save Dotrar/f6f9a4fc0d691cf7f6f825c0e17ce6b5 to your computer and use it in GitHub Desktop.
Pytest Reloader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Pytest reloader: | |
author: Dre | |
place this file in your source directory (ie: src/confteset.py) which will auto-load by pytest. | |
when running pytests with the --pdb option, when leaving the debugger from test-failure, this plugin will re-load the | |
test and run it to see if any code changes have improved. | |
currently only reloads the test. | |
""" | |
import importlib | |
import inspect | |
import pytest | |
from _pytest.runner import runtestprotocol | |
def _check_options_have_pdb(config) -> bool: | |
val = config.getvalue | |
if not val("collectonly"): | |
if config.option.usepdb: # a core option | |
return True | |
return False | |
@pytest.hookimpl() | |
def pytest_enter_pdb(config, pdb): | |
print("##" * 10) | |
print("Running in reloader mode:") | |
print(" make changes to the source code") | |
print(" then use 'continue' or 'return' in pdb") | |
print(" to reload and re-test your changes.") | |
print("") | |
print(" use 'quit' to quit entirely.") | |
print("##" * 10) | |
@pytest.hookimpl() | |
def pytest_runtest_protocol(item, nextitem): | |
if not _check_options_have_pdb(item.session.config): | |
return | |
while True: | |
reports = runtestprotocol(item, log=False, nextitem=nextitem) | |
if len(reports) != 3: | |
# something else happened and we don't care | |
return | |
call = reports[1] | |
if call.outcome == "passed": | |
return | |
# the test didn't pass, so let's reload and re-try the test. | |
test_func = item._obj | |
func_path = test_func.__qualname__.split(".") | |
# re-import the parent module | |
func = importlib.reload(inspect.getmodule(test_func)) | |
# load reference to new function | |
while func_path: | |
p = func_path[0] | |
func = getattr(func, p) | |
# test classes need to be instantiated. | |
if inspect.isclass(func): | |
func = func() | |
func_path.remove(p) | |
item._obj = func | |
print( | |
""" | |
################# | |
Reloaded latest code changes. | |
################# | |
""" | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment