validmind 1.8.0__py3-none-any.whl → 1.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- validmind/__init__.py +8 -1
- validmind/client.py +48 -41
- validmind/test_plans/__init__.py +0 -4
- validmind/test_plans/binary_classifier.py +0 -15
- validmind/test_plans/tabular_datasets.py +0 -13
- validmind/test_suites/__init__.py +73 -0
- validmind/test_suites/test_suites.py +48 -0
- validmind/vm_models/__init__.py +2 -0
- validmind/vm_models/test_suite.py +57 -0
- {validmind-1.8.0.dist-info → validmind-1.8.1.dist-info}/METADATA +1 -1
- {validmind-1.8.0.dist-info → validmind-1.8.1.dist-info}/RECORD +12 -9
- {validmind-1.8.0.dist-info → validmind-1.8.1.dist-info}/WHEEL +0 -0
validmind/__init__.py
CHANGED
@@ -30,7 +30,13 @@ from .api_client import ( # noqa: E402
|
|
30
30
|
log_figure,
|
31
31
|
)
|
32
32
|
|
33
|
-
from .client import
|
33
|
+
from .client import ( # noqa: E402
|
34
|
+
init_dataset,
|
35
|
+
init_model,
|
36
|
+
init_r_model,
|
37
|
+
run_test_plan,
|
38
|
+
run_test_suite,
|
39
|
+
)
|
34
40
|
|
35
41
|
# TODO: need to fix this import * situation
|
36
42
|
from .data_validation import * # noqa
|
@@ -45,6 +51,7 @@ __all__ = [ # noqa
|
|
45
51
|
"init_r_model",
|
46
52
|
"test_plans",
|
47
53
|
"run_test_plan",
|
54
|
+
"run_test_suite",
|
48
55
|
# Framework Logging API
|
49
56
|
"log_dataset",
|
50
57
|
"log_figure",
|
validmind/client.py
CHANGED
@@ -8,7 +8,8 @@ import xgboost as xgb
|
|
8
8
|
from sklearn.linear_model import LinearRegression, LogisticRegression
|
9
9
|
|
10
10
|
# from .model_validation import evaluate_model as mod_evaluate_model
|
11
|
-
from .test_plans import get_by_name
|
11
|
+
from .test_plans import get_by_name as get_test_plan_by_name
|
12
|
+
from .test_suites import get_by_name as get_test_suite_by_name
|
12
13
|
from .vm_models import (
|
13
14
|
Dataset,
|
14
15
|
DatasetTargets,
|
@@ -16,6 +17,7 @@ from .vm_models import (
|
|
16
17
|
ModelAttributes,
|
17
18
|
R_MODEL_TYPES,
|
18
19
|
TestPlan,
|
20
|
+
TestSuite,
|
19
21
|
)
|
20
22
|
|
21
23
|
|
@@ -65,10 +67,10 @@ def init_dataset(
|
|
65
67
|
|
66
68
|
|
67
69
|
def init_model(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
model: object,
|
71
|
+
train_ds: Dataset = None,
|
72
|
+
test_ds: Dataset = None,
|
73
|
+
validation_ds: Dataset = None,
|
72
74
|
) -> Model:
|
73
75
|
"""
|
74
76
|
Initializes a VM Model, which can then be passed to other functions
|
@@ -92,7 +94,9 @@ def init_model(
|
|
92
94
|
)
|
93
95
|
)
|
94
96
|
|
95
|
-
return Model.init_vm_model(
|
97
|
+
return Model.init_vm_model(
|
98
|
+
model, train_ds, test_ds, validation_ds, attributes=ModelAttributes()
|
99
|
+
)
|
96
100
|
|
97
101
|
|
98
102
|
def init_r_model(model_path: str, model_type: str) -> Model:
|
@@ -193,7 +197,7 @@ def run_test_plan(test_plan_name, send=True, **kwargs):
|
|
193
197
|
dict: A dictionary of test results
|
194
198
|
"""
|
195
199
|
try:
|
196
|
-
Plan: TestPlan =
|
200
|
+
Plan: TestPlan = get_test_plan_by_name(test_plan_name)
|
197
201
|
except ValueError as exc:
|
198
202
|
raise ValueError(
|
199
203
|
"Error retrieving test plan {}. {}".format(test_plan_name, str(exc))
|
@@ -211,37 +215,40 @@ def run_test_plan(test_plan_name, send=True, **kwargs):
|
|
211
215
|
return plan
|
212
216
|
|
213
217
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
218
|
+
def run_test_suite(test_suite_name, send=True, **kwargs):
|
219
|
+
"""High Level function for running a test suite
|
220
|
+
|
221
|
+
This function provides a high level interface for running a test suite. A test suite is
|
222
|
+
a collection of test plans. This function will automatically find the correct test suite
|
223
|
+
class based on the test_suite_name, initialize each of the test plans, and run them.
|
224
|
+
|
225
|
+
Args:
|
226
|
+
test_suite_name (str): The test suite name (e.g. 'binary_classifier_full_suite')
|
227
|
+
send (bool, optional): Whether to post the test results to the API. send=False is useful for testing. Defaults to True.
|
228
|
+
**kwargs: Additional keyword arguments to pass to the test suite. These will provide
|
229
|
+
the TestSuite instance with the necessary context to run the tests. e.g. dataset, model etc.
|
230
|
+
See the documentation for the specific test plan, metric or threshold test for more details.
|
231
|
+
|
232
|
+
Raises:
|
233
|
+
ValueError: If the test suite name is not found or if there is an error initializing the test suite
|
234
|
+
|
235
|
+
Returns:
|
236
|
+
TestSuite: the TestSuite instance
|
237
|
+
"""
|
238
|
+
try:
|
239
|
+
Suite: TestSuite = get_test_suite_by_name(test_suite_name)
|
240
|
+
except ValueError as exc:
|
241
|
+
raise ValueError(
|
242
|
+
"Error retrieving test suite {}. {}".format(test_suite_name, str(exc))
|
243
|
+
)
|
244
|
+
|
245
|
+
try:
|
246
|
+
suite = Suite(**kwargs)
|
247
|
+
except ValueError as exc:
|
248
|
+
raise ValueError(
|
249
|
+
"Error initializing test suite {}. {}".format(test_suite_name, str(exc))
|
250
|
+
)
|
251
|
+
|
252
|
+
suite.run(send=send)
|
253
|
+
|
254
|
+
return suite
|
validmind/test_plans/__init__.py
CHANGED
@@ -8,12 +8,10 @@ import tabulate
|
|
8
8
|
from ..vm_models import TestPlan
|
9
9
|
from .binary_classifier import (
|
10
10
|
BinaryClassifierMetrics,
|
11
|
-
BinaryClassifier,
|
12
11
|
BinaryClassifierPerformance,
|
13
12
|
BinaryClassifierDiagnosis,
|
14
13
|
)
|
15
14
|
from .tabular_datasets import (
|
16
|
-
TabularDataset,
|
17
15
|
TabularDataQuality,
|
18
16
|
TabularDatasetDescription,
|
19
17
|
TimeSeriesDataQuality,
|
@@ -39,8 +37,6 @@ core_test_plans = {
|
|
39
37
|
"binary_classifier_metrics": BinaryClassifierMetrics,
|
40
38
|
"binary_classifier_validation": BinaryClassifierPerformance,
|
41
39
|
"binary_classifier_model_diagnosis": BinaryClassifierDiagnosis,
|
42
|
-
"binary_classifier": BinaryClassifier,
|
43
|
-
"tabular_dataset": TabularDataset,
|
44
40
|
"tabular_dataset_description": TabularDatasetDescription,
|
45
41
|
"tabular_data_quality": TabularDataQuality,
|
46
42
|
"normality_test_plan": NormalityTestPlan,
|
@@ -81,18 +81,3 @@ class BinaryClassifierDiagnosis(TestPlan):
|
|
81
81
|
name = "binary_classifier_model_diagnosis"
|
82
82
|
required_context = ["model"]
|
83
83
|
tests = [OverfitDiagnosis, WeakspotsDiagnosis, RobustnessDiagnosis]
|
84
|
-
|
85
|
-
|
86
|
-
class BinaryClassifier(TestPlan):
|
87
|
-
"""
|
88
|
-
Test plan for sklearn classifier models that includes
|
89
|
-
both metrics and validation tests
|
90
|
-
"""
|
91
|
-
|
92
|
-
name = "binary_classifier"
|
93
|
-
required_context = ["model"]
|
94
|
-
test_plans = [
|
95
|
-
BinaryClassifierMetrics,
|
96
|
-
BinaryClassifierPerformance,
|
97
|
-
BinaryClassifierDiagnosis,
|
98
|
-
]
|
@@ -72,19 +72,6 @@ class TimeSeriesDataQuality(TestPlan):
|
|
72
72
|
tests = [TimeSeriesOutliers, TimeSeriesMissingValues, TimeSeriesFrequency]
|
73
73
|
|
74
74
|
|
75
|
-
class TabularDataset(TestPlan):
|
76
|
-
"""
|
77
|
-
Test plan for generic tabular datasets
|
78
|
-
"""
|
79
|
-
|
80
|
-
name = "tabular_dataset"
|
81
|
-
required_context = ["dataset"]
|
82
|
-
test_plans = [
|
83
|
-
TabularDatasetDescription,
|
84
|
-
TabularDataQuality,
|
85
|
-
]
|
86
|
-
|
87
|
-
|
88
75
|
class TimeSeriesDataset(TestPlan):
|
89
76
|
"""
|
90
77
|
Test plan for time series datasets
|
@@ -0,0 +1,73 @@
|
|
1
|
+
"""
|
2
|
+
Entrypoint for test suites.
|
3
|
+
"""
|
4
|
+
import tabulate
|
5
|
+
|
6
|
+
from .test_suites import (
|
7
|
+
BinaryClassifierFullSuite,
|
8
|
+
BinaryClassifierModelValidation,
|
9
|
+
TabularDataset,
|
10
|
+
)
|
11
|
+
from ..vm_models import TestSuite
|
12
|
+
|
13
|
+
core_test_suites = {
|
14
|
+
"binary_classifier_full_suite": BinaryClassifierFullSuite,
|
15
|
+
"binary_classifier_model_validation": BinaryClassifierModelValidation,
|
16
|
+
"tabular_dataset": TabularDataset,
|
17
|
+
}
|
18
|
+
|
19
|
+
# These test suites can be added by the user
|
20
|
+
custom_test_suites = {}
|
21
|
+
|
22
|
+
|
23
|
+
def _get_all_test_suites():
|
24
|
+
"""
|
25
|
+
Returns a dictionary of all test suites.
|
26
|
+
|
27
|
+
Merge the core and custom test suites, with the custom suites
|
28
|
+
taking precedence, i.e. allowing overriding of core test suites
|
29
|
+
"""
|
30
|
+
return {**core_test_suites, **custom_test_suites}
|
31
|
+
|
32
|
+
|
33
|
+
def get_by_name(name: str):
|
34
|
+
"""
|
35
|
+
Returns the test suite by name
|
36
|
+
"""
|
37
|
+
all_test_suites = _get_all_test_suites()
|
38
|
+
if name in all_test_suites:
|
39
|
+
return all_test_suites[name]
|
40
|
+
|
41
|
+
raise ValueError(f"Test suite with name: '{name}' not found")
|
42
|
+
|
43
|
+
|
44
|
+
def list_suites(pretty: bool = True):
|
45
|
+
"""
|
46
|
+
Returns a list of all available test suites
|
47
|
+
"""
|
48
|
+
|
49
|
+
all_test_suites = _get_all_test_suites()
|
50
|
+
|
51
|
+
if not pretty:
|
52
|
+
return list(all_test_suites.keys())
|
53
|
+
|
54
|
+
table = []
|
55
|
+
for name, test_suite in all_test_suites.items():
|
56
|
+
table.append(
|
57
|
+
{
|
58
|
+
"ID": name,
|
59
|
+
"Name": test_suite.__name__,
|
60
|
+
"Description": test_suite.__doc__.strip(),
|
61
|
+
"Test Plans": ", ".join(test_suite.test_plans),
|
62
|
+
}
|
63
|
+
)
|
64
|
+
|
65
|
+
return tabulate.tabulate(table, headers="keys", tablefmt="html")
|
66
|
+
|
67
|
+
|
68
|
+
def register_test_suite(suite_id: str, suite: TestSuite):
|
69
|
+
"""
|
70
|
+
Registers a custom test suite
|
71
|
+
"""
|
72
|
+
custom_test_suites[suite_id] = suite
|
73
|
+
print(f"Registered test suite: {suite_id}")
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"""
|
2
|
+
Default test suites provided by the developer framework.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from ..vm_models import TestSuite
|
6
|
+
|
7
|
+
|
8
|
+
class TabularDataset(TestSuite):
|
9
|
+
"""
|
10
|
+
Test suite for tabular datasets.
|
11
|
+
"""
|
12
|
+
|
13
|
+
required_context = ["dataset"]
|
14
|
+
|
15
|
+
test_plans = [
|
16
|
+
"tabular_dataset_description",
|
17
|
+
"tabular_data_quality",
|
18
|
+
]
|
19
|
+
|
20
|
+
|
21
|
+
class BinaryClassifierModelValidation(TestSuite):
|
22
|
+
"""
|
23
|
+
Test suite for binary classification models.
|
24
|
+
"""
|
25
|
+
|
26
|
+
required_context = ["model"]
|
27
|
+
|
28
|
+
test_plans = [
|
29
|
+
"binary_classifier_metrics",
|
30
|
+
"binary_classifier_validation",
|
31
|
+
"binary_classifier_model_diagnosis",
|
32
|
+
]
|
33
|
+
|
34
|
+
|
35
|
+
class BinaryClassifierFullSuite(TestSuite):
|
36
|
+
"""
|
37
|
+
Full test suite for binary classification models.
|
38
|
+
"""
|
39
|
+
|
40
|
+
required_context = ["dataset", "model"]
|
41
|
+
|
42
|
+
test_plans = [
|
43
|
+
"tabular_dataset_description",
|
44
|
+
"tabular_data_quality",
|
45
|
+
"binary_classifier_metrics",
|
46
|
+
"binary_classifier_validation",
|
47
|
+
"binary_classifier_model_diagnosis",
|
48
|
+
]
|
validmind/vm_models/__init__.py
CHANGED
@@ -17,6 +17,7 @@ from .test_plan_result import (
|
|
17
17
|
TestPlanTestResult,
|
18
18
|
)
|
19
19
|
from .test_result import TestResult, TestResults
|
20
|
+
from .test_suite import TestSuite
|
20
21
|
from .threshold_test import ThresholdTest
|
21
22
|
|
22
23
|
__all__ = [
|
@@ -40,5 +41,6 @@ __all__ = [
|
|
40
41
|
"TestPlanTestResult",
|
41
42
|
"TestResult",
|
42
43
|
"TestResults",
|
44
|
+
"TestSuite",
|
43
45
|
"ThresholdTest",
|
44
46
|
]
|
@@ -0,0 +1,57 @@
|
|
1
|
+
"""
|
2
|
+
A TestSuite is a collection of TestPlans. It is a helpful way to organize
|
3
|
+
TestPlans that are related to each other. For example, a TestSuite could be
|
4
|
+
created for a specific use case or model methodology, to run a colllection
|
5
|
+
of plans for data validation and model validation with a single function call.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from dataclasses import dataclass
|
9
|
+
from typing import ClassVar, List
|
10
|
+
|
11
|
+
from .test_context import TestContext
|
12
|
+
from .test_plan import TestPlan
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass
|
16
|
+
class TestSuite(TestPlan):
|
17
|
+
"""
|
18
|
+
Base class for test suites. Test suites are used to define any
|
19
|
+
arbitrary grouping of test plans that will be run on a dataset and/or model.
|
20
|
+
"""
|
21
|
+
|
22
|
+
test_plans: ClassVar[List[str]] = []
|
23
|
+
# Stores a reference to the child test plan instances
|
24
|
+
# so we can access their results after running the test suite
|
25
|
+
_test_plan_instances: List[object] = None
|
26
|
+
|
27
|
+
def run(self, send=True):
|
28
|
+
"""
|
29
|
+
Runs the test suite.
|
30
|
+
"""
|
31
|
+
# Avoid circular import
|
32
|
+
from ..test_plans import get_by_name
|
33
|
+
|
34
|
+
self._test_plan_instances = []
|
35
|
+
|
36
|
+
if self.test_context is None:
|
37
|
+
self.test_context = TestContext(
|
38
|
+
dataset=self.dataset,
|
39
|
+
model=self.model,
|
40
|
+
models=self.models,
|
41
|
+
)
|
42
|
+
|
43
|
+
for test_plan_id in self.test_plans:
|
44
|
+
test_plan = get_by_name(test_plan_id)
|
45
|
+
test_plan_instance = test_plan(
|
46
|
+
config=self.config,
|
47
|
+
test_context=self.test_context,
|
48
|
+
)
|
49
|
+
test_plan_instance.run(send=send)
|
50
|
+
self._test_plan_instances.append(test_plan_instance)
|
51
|
+
|
52
|
+
@property
|
53
|
+
def results(self):
|
54
|
+
"""
|
55
|
+
Returns the results of the test suite.
|
56
|
+
"""
|
57
|
+
return [test_plan.results for test_plan in self._test_plan_instances]
|
@@ -1,6 +1,6 @@
|
|
1
|
-
validmind/__init__.py,sha256=
|
1
|
+
validmind/__init__.py,sha256=ND6a4RZrm1QFdYvDnGqhfwoXFsC762CJrUzdPdcVtp0,1443
|
2
2
|
validmind/api_client.py,sha256=fqEWQii5H5uS4gbjm2X05mKKfPGeQiV6VkuMf_fC2Gw,11353
|
3
|
-
validmind/client.py,sha256=
|
3
|
+
validmind/client.py,sha256=cwk8swBmclmT4POTUsRdGXAKIg5IxzfOvYPXrRVvKQM,9190
|
4
4
|
validmind/data_validation/__init__.py,sha256=xytRpsfQ86fDnIZRoAO7GMVVU_TwWVMXxSCwm0mb45I,590
|
5
5
|
validmind/data_validation/metrics.py,sha256=I-q_fQ4daFneSAS8-hdVw7SMwrUnSv3m_RdcOsxDB10,35109
|
6
6
|
validmind/data_validation/threshold_tests.py,sha256=azKHJ31HTxffq8_rVCpsfXIumJ9i02HwpgPXsAKm5Ck,24265
|
@@ -35,13 +35,15 @@ validmind/model_validation/statsmodels/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
|
|
35
35
|
validmind/model_validation/statsmodels/metrics.py,sha256=wGEDlqHYVxpzUCbheYRy5Y8OiUs7wwHuxFwdnrhSctA,28009
|
36
36
|
validmind/model_validation/statsmodels/threshold_tests.py,sha256=SyEv7oaNIgiQ1ML3dQrGN54pSP88j9htOy4V2l4Ipwk,1317
|
37
37
|
validmind/model_validation/utils.py,sha256=lOq-C_mucS5JZ-7V43PnSqYkGc5ybdGDbzhclWp4V3A,1657
|
38
|
-
validmind/test_plans/__init__.py,sha256=
|
39
|
-
validmind/test_plans/binary_classifier.py,sha256=
|
38
|
+
validmind/test_plans/__init__.py,sha256=elptQlHZ1YK55Rm2nQd391gpGjbXakzC9xDk2Txj7dw,5251
|
39
|
+
validmind/test_plans/binary_classifier.py,sha256=x5vUXPD3Xfqxv6041lGfyzo3v8a0OzRcsaspajEqmyg,1985
|
40
40
|
validmind/test_plans/statsmodels_timeseries.py,sha256=bEHwL_RJY5SoiUQnbM0SrGI6dcW2jJmasoH3CAYvBYQ,2836
|
41
|
-
validmind/test_plans/tabular_datasets.py,sha256=
|
41
|
+
validmind/test_plans/tabular_datasets.py,sha256=Eoz_Rbf2JKsD61XI6ZAti10uBaTa22Y8pkyJ7RUMGUc,1822
|
42
42
|
validmind/test_plans/time_series.py,sha256=ecBVWUh4fAS8g6ZAUQwbmuaVo7q7tyMVrCyp1TV8RD8,6821
|
43
|
+
validmind/test_suites/__init__.py,sha256=rojE4xXj0LPq4BUKWkUe6N_Z3RDvjztmY3f4g28kMOw,1825
|
44
|
+
validmind/test_suites/test_suites.py,sha256=XLhRLNKagrlBhVrGwIp965O7KqTpPUVVHdYGFGvc1A0,1000
|
43
45
|
validmind/utils.py,sha256=6KnbRTUJt6dRXbNtMzLySkJ3hnVC5f_e4qP-MEIDUbk,6465
|
44
|
-
validmind/vm_models/__init__.py,sha256=
|
46
|
+
validmind/vm_models/__init__.py,sha256=6Rnzxn5aaHYFkq1llchPNmdjSVJXh8mHSWEqW1gQs1M,1116
|
45
47
|
validmind/vm_models/dataset.py,sha256=CE2mJwT27HMKCJAE9ssRb0gh8skdrSSyYiOk3v4QCSw,10425
|
46
48
|
validmind/vm_models/dataset_utils.py,sha256=xWq6dbxe9fCUdpKCiEFvbxhy9t7cOKh0boS-zw6ynZo,8287
|
47
49
|
validmind/vm_models/figure.py,sha256=EarfMm49J2BWf6UhsMFGr3VSdGu8v2ZewzArKKp_LfU,592
|
@@ -54,7 +56,8 @@ validmind/vm_models/test_context.py,sha256=nWiTIORPNEl7mKkYme8n2QaJyAotp034A2NK3
|
|
54
56
|
validmind/vm_models/test_plan.py,sha256=qGCftt01Yvzz9RbFGDo4uTWT9XyDb4doTxq3HxC65Mk,9846
|
55
57
|
validmind/vm_models/test_plan_result.py,sha256=STdD-l0d68ogJet7T5j06YhCTtrGkGP248aiaHfxq6k,19074
|
56
58
|
validmind/vm_models/test_result.py,sha256=jiX8yb1NptBXZQ_pOyHloc8I6yS6zamYm0j9OWUqrHs,1698
|
59
|
+
validmind/vm_models/test_suite.py,sha256=cxyVF8cY1_ycpRRzvDHcIw3kTOUWhSYk6ObtyyB4xdg,1811
|
57
60
|
validmind/vm_models/threshold_test.py,sha256=uqTqHDf443_Xm2J4G5KBnMH0GLRVVIpv6V-A3f-tSvE,3621
|
58
|
-
validmind-1.8.
|
59
|
-
validmind-1.8.
|
60
|
-
validmind-1.8.
|
61
|
+
validmind-1.8.1.dist-info/METADATA,sha256=BIfuQCYGrkDXHtwjIMFTJ8vgjNR862_hMASgxqGaiCk,1385
|
62
|
+
validmind-1.8.1.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
63
|
+
validmind-1.8.1.dist-info/RECORD,,
|
File without changes
|