-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MNT] Differential testing of estimators (#96)
This PR introduces the differential testing from `sktime` to the PR CI, to test only estimators from modules that have changed. This does not affect the release CI, which runs the tests for all estimators in `sktime`.
- Loading branch information
Showing
5 changed files
with
148 additions
and
3 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"""Main configuration file for pytest. | ||
Contents: | ||
adds an --only_changed_modules option to pytest | ||
this allows to turn on/off differential testing (for shorter runtime) | ||
"on" condition ensures that only estimators are tested that have changed, | ||
more precisely, only estimators whose class is in a module | ||
that has changed compared to the main branch | ||
by default, this is off, including for default local runs of pytest | ||
""" | ||
# copyright: skpro developers, BSD-3-Clause License (see LICENSE file) | ||
|
||
__author__ = ["fkiraly"] | ||
|
||
|
||
def pytest_addoption(parser): | ||
"""Pytest command line parser options adder.""" | ||
parser.addoption( | ||
"--only_changed_modules", | ||
default=False, | ||
help="test only estimators from modules that have changed compared to main", | ||
) | ||
|
||
|
||
def pytest_configure(config): | ||
"""Pytest configuration preamble.""" | ||
from skpro.tests import test_all_estimators | ||
|
||
if config.getoption("--only_changed_modules") in [True, "True"]: | ||
test_all_estimators.ONLY_CHANGED_MODULES = True |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
"""Git related utilities to identify changed modules.""" | ||
|
||
__author__ = ["fkiraly"] | ||
__all__ = [] | ||
|
||
import importlib.util | ||
import inspect | ||
import subprocess | ||
|
||
|
||
def get_module_from_class(cls): | ||
"""Get full parent module string from class. | ||
Parameters | ||
---------- | ||
cls : class | ||
class to get module string from, e.g., NaiveForecaster | ||
Returns | ||
------- | ||
str : module string, e.g., sktime.forecasting.naive | ||
""" | ||
module = inspect.getmodule(cls) | ||
return module.__name__ if module else None | ||
|
||
|
||
def get_path_from_module(module_str): | ||
r"""Get local path string from module string. | ||
Parameters | ||
---------- | ||
module_str : str | ||
module string, e.g., sktime.forecasting.naive | ||
Returns | ||
------- | ||
str : local path string, e.g., sktime\forecasting\naive.py | ||
""" | ||
try: | ||
module_spec = importlib.util.find_spec(module_str) | ||
if module_spec is None: | ||
raise ImportError( | ||
f"Error in get_path_from_module, module '{module_str}' not found." | ||
) | ||
return module_spec.origin | ||
except Exception as e: | ||
raise ImportError(f"Error finding module '{module_str}'") from e | ||
|
||
|
||
def is_module_changed(module_str): | ||
"""Check if a module has changed compared to the main branch. | ||
Parameters | ||
---------- | ||
module_str : str | ||
module string, e.g., sktime.forecasting.naive | ||
""" | ||
module_file_path = get_path_from_module(module_str) | ||
cmd = f"git diff remotes/origin/main -- {module_file_path}" | ||
try: | ||
output = subprocess.check_output(cmd, shell=True, text=True) | ||
return bool(output) | ||
except subprocess.CalledProcessError: | ||
return True | ||
|
||
|
||
def is_class_changed(cls): | ||
"""Check if a class' parent module has changed compared to the main branch. | ||
Parameters | ||
---------- | ||
cls : class | ||
class to get module string from, e.g., NaiveForecaster | ||
Returns | ||
------- | ||
bool : True if changed, False otherwise | ||
""" | ||
module_str = get_module_from_class(cls) | ||
return is_module_changed(module_str) |