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 CHANGED
@@ -30,7 +30,13 @@ from .api_client import ( # noqa: E402
30
30
  log_figure,
31
31
  )
32
32
 
33
- from .client import init_dataset, init_model, init_r_model, run_test_plan # noqa: E402
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
- model: object,
69
- train_ds: Dataset = None,
70
- test_ds: Dataset = None,
71
- validation_ds: Dataset = None
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(model, train_ds, test_ds, validation_ds, attributes=ModelAttributes())
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 = get_by_name(test_plan_name)
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
- # def evaluate_model(model, train_set, val_set, test_set, eval_opts=None, send=True):
215
- # """
216
- # Evaluates a model and logs results to the ValidMind API. This function will log information
217
- # about the trained model (parameters, etc.), training metrics, test metrics, and run model
218
- # evaluation tests.
219
-
220
- # :param model: The model to evaluate. Only scikit-learn and XGBoost models are supported at the moment
221
- # :param (pd.DataFrame, pd.DataFrame) train_set: (x_train, y_train) tuple
222
- # :param (pd.DataFrame, pd.DataFrame) val_set: (x_val, y_val) tuple
223
- # :param (pd.DataFrame, pd.DataFrame) test_set: (x_test, y_test) tuple
224
- # :param dict eval_opts: A dictionary of options for the model evaluation
225
- # :param bool send: Whether to post the test results to the API. send=False is useful for testing
226
- # """
227
- # print("Logging model metadata and parameters...")
228
- # log_model(model)
229
-
230
- # print("Extracting training/validation set metrics from trained model...")
231
- # x_train, y_train = train_set
232
- # x_val, y_val = val_set
233
-
234
- # log_training_metrics(
235
- # model, x_train.copy(), y_train.copy(), x_val.copy(), y_val.copy()
236
- # )
237
-
238
- # print("Running model evaluation tests...")
239
- # eval_results = mod_evaluate_model(
240
- # model,
241
- # test_set=test_set,
242
- # train_set=train_set,
243
- # eval_opts=eval_opts,
244
- # send=send,
245
- # )
246
-
247
- # return eval_results
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
@@ -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
+ ]
@@ -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
1
  Metadata-Version: 2.1
2
2
  Name: validmind
3
- Version: 1.8.0
3
+ Version: 1.8.1
4
4
  Summary: ValidMind Developer Framework
5
5
  Author: Andres Rodriguez
6
6
  Author-email: andres@validmind.ai
@@ -1,6 +1,6 @@
1
- validmind/__init__.py,sha256=_-1gzCQo2v2TEjQPyRD2SLJ7UCOiaPVFWnTkxMf7gfY,1380
1
+ validmind/__init__.py,sha256=ND6a4RZrm1QFdYvDnGqhfwoXFsC762CJrUzdPdcVtp0,1443
2
2
  validmind/api_client.py,sha256=fqEWQii5H5uS4gbjm2X05mKKfPGeQiV6VkuMf_fC2Gw,11353
3
- validmind/client.py,sha256=P5UC4BVrts1S83xfPu37QZvtETuVcIbEOT7eEN_oPhw,8945
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=HUlON7orGplvoGmszwhm1q1Keu9Lbw8nv5vWfsAROTE,5375
39
- validmind/test_plans/binary_classifier.py,sha256=ct_ZWwxNM1K245DA8wyoNtu2eDzJ92r-eDgKES_KKEE,2328
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=5uyGOGnt5ngTsSJ-0DdonAlbErhprq9dZdZ2c0EXKik,2068
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=9KA42gT5a9ocSfum5b3UaXHxuaI_NWiKAXalOWg9G3E,1065
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.0.dist-info/METADATA,sha256=fJqqUj7v2oppsz8HCRoFhxcToRvI4Fl3nfI5QhLuw7s,1385
59
- validmind-1.8.0.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
60
- validmind-1.8.0.dist-info/RECORD,,
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,,