Core¶
modeltest
¶
ModelSuite(name='suite', tests=None)
¶
A collection of tests run together against a model + data.
Collect tests to run together against one model + dataset.
Args:
name: Label used in reports and JUnit XML.
tests: Initial tests; more can be added with
add_test / add_tests.
Source code in modeltest/core/base.py
231 232 233 234 235 236 237 238 239 240 | |
add_test(test)
¶
Append a test to the suite. Returns self, for chaining.
Source code in modeltest/core/base.py
242 243 244 245 | |
add_tests(*tests)
¶
Append several tests at once. Returns self, for chaining.
Source code in modeltest/core/base.py
247 248 249 250 | |
run(model, X_val, y_val, X_train=None, y_train=None, **metadata)
¶
Run every test against a model and validation data.
Builds a single TestContext (with the shared prediction cache)
and passes it to all tests, so predictions are computed once.
Args:
model: The model under test (wrapped automatically).
X_val: Validation features (DataFrame or array).
y_val: Ground-truth labels for the validation set.
X_train: Optional training features — required by the
drift tests.
y_train: Optional training labels.
**metadata: Extra key/value pairs stored in the context, e.g.
model_name="fraud_rf".
Returns:
Aggregate outcome with one TestResult per test.
Source code in modeltest/core/base.py
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | |
ModelTest
¶
Base class for all model tests.
Subclasses override test(self, ctx). Raising AssertionError (or any
assert failure) marks the test as FAILED; raising anything else marks
it as ERROR. Returning a :class:TestResult lets a test fully control the
outcome (useful for warning-only / non-blocking checks).
test(ctx)
¶
Run the check. Subclasses must override this.
Args: ctx: Context with the model, data and shared prediction cache.
Returns:
Normally nothing: pass/fail is expressed via exceptions. Return
a TestResult to fully control the outcome (warning-only or
non-blocking checks).
Raises: AssertionError: Marks the test as FAILED. Exception: Anything else marks it as ERROR.
Source code in modeltest/core/base.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
run(ctx)
¶
Execute test and translate the outcome into a TestResult.
Times the call and maps exceptions to statuses: an
AssertionError becomes FAILED, any other exception becomes
ERROR.
Args: ctx: Context to run against.
Returns:
The outcome for this test, named after self.name or the
class name when no explicit name was set.
Source code in modeltest/core/base.py
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
SuiteResult(suite_name, results=list())
dataclass
¶
Aggregate outcome of running every test in a suite.
passed
property
¶
True when every test in the suite passed.
num_passed
property
¶
Count of PASSED tests.
num_failed
property
¶
Count of tests that did not pass (FAILED, ERROR or SKIPPED).
report(style='table')
¶
Render the suite outcome.
Args:
style: "table" (console), "json" (machine-readable) or
"junit" (XML for CI test reporters).
Returns: The rendered report as a string.
Source code in modeltest/core/base.py
314 315 316 317 318 319 320 321 322 323 324 325 326 | |
TestContext(model, X_val, y_val, X_train=None, y_train=None, metadata=dict(), cache_predictions=True, _cache=None, _wrapper=None)
dataclass
¶
Everything a test may need at runtime.
A unified context (rather than a loose model, X, y signature) lets tests
grow (drift needs train vs val; explainability needs metadata) without
breaking the base API.
model_name
property
¶
Name of the model under test.
Uses the model_name metadata key when present, falling back to
the wrapped model's class name.
predict(X=None)
¶
Predict with caching.
Delegates to the model via the framework adapter while transparently
dropping non-feature columns (via model_features). When
cache_predictions is on, the result is keyed by a content hash of
the input so that multiple tests predicting on the same data run the
model only once per suite.
Passing X=None predicts on self.X_val.
Source code in modeltest/core/base.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |
predict_proba(X=None)
¶
Probability estimates via the wrapper (or None if unsupported).
Source code in modeltest/core/base.py
107 108 109 110 111 112 | |
TestResult(name, status, detail='', duration_ms=0.0, metrics=dict())
dataclass
¶
Outcome of running a single test.
passed
property
¶
Whether the test passed (status is PASSED).
register(type_name, cls)
¶
Map a YAML type string to a custom test class.
Custom tests must subclass :class:modeltest.ModelTest. Registering
before :func:load_suite_yaml lets a suite reference your test by name::
from modeltest.config import register
register("my_error_check", MyErrorCheck)
# suite.yaml
# suite:
# tests:
# - type: my_error_check
# params: {max_errors: 5}
Source code in modeltest/config.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
unregister(type_name)
¶
Remove a previously registered type (built-ins included).
Source code in modeltest/config.py
96 97 98 | |
run_suite(suite, ctx)
¶
Run every test in a suite against one shared context.
Sharing the context is what makes prediction caching work across tests: the first prediction is computed and every later test predicting on the same data reuses it.
Args: suite: The suite to execute. ctx: The (single) context handed to every test.
Returns:
Aggregate outcome with one TestResult per test, in order.
Source code in modeltest/core/runner.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
run_test(test, ctx)
¶
Run a single test against a context.
Args: test: The test to execute. ctx: Context with model, data and the shared prediction cache.
Returns:
The test's TestResult.
Source code in modeltest/core/runner.py
8 9 10 11 12 13 14 15 16 17 18 | |
modeltest.core.base
¶
Core primitives: ModelTest, TestContext, TestResult, ModelSuite.
The design mirrors how pytest structures tests but is oriented to ML:
each test receives a rich context (model + data + metadata) instead of a
bare function signature. A test passes by returning normally and fails
by raising an assertion / returning a TestResult with passed=False.
TestStatus
¶
Bases: str, Enum
Outcome status of a single test run.
Attributes:
PASSED: The test returned normally — every assertion held.
FAILED: An AssertionError was raised — the contract is violated.
ERROR: Something else went wrong (bad config, missing column...).
SKIPPED: The test decided not to run.
TestContext(model, X_val, y_val, X_train=None, y_train=None, metadata=dict(), cache_predictions=True, _cache=None, _wrapper=None)
dataclass
¶
Everything a test may need at runtime.
A unified context (rather than a loose model, X, y signature) lets tests
grow (drift needs train vs val; explainability needs metadata) without
breaking the base API.
model_name
property
¶
Name of the model under test.
Uses the model_name metadata key when present, falling back to
the wrapped model's class name.
predict(X=None)
¶
Predict with caching.
Delegates to the model via the framework adapter while transparently
dropping non-feature columns (via model_features). When
cache_predictions is on, the result is keyed by a content hash of
the input so that multiple tests predicting on the same data run the
model only once per suite.
Passing X=None predicts on self.X_val.
Source code in modeltest/core/base.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |
predict_proba(X=None)
¶
Probability estimates via the wrapper (or None if unsupported).
Source code in modeltest/core/base.py
107 108 109 110 111 112 | |
TestResult(name, status, detail='', duration_ms=0.0, metrics=dict())
dataclass
¶
Outcome of running a single test.
passed
property
¶
Whether the test passed (status is PASSED).
ModelTest
¶
Base class for all model tests.
Subclasses override test(self, ctx). Raising AssertionError (or any
assert failure) marks the test as FAILED; raising anything else marks
it as ERROR. Returning a :class:TestResult lets a test fully control the
outcome (useful for warning-only / non-blocking checks).
test(ctx)
¶
Run the check. Subclasses must override this.
Args: ctx: Context with the model, data and shared prediction cache.
Returns:
Normally nothing: pass/fail is expressed via exceptions. Return
a TestResult to fully control the outcome (warning-only or
non-blocking checks).
Raises: AssertionError: Marks the test as FAILED. Exception: Anything else marks it as ERROR.
Source code in modeltest/core/base.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
run(ctx)
¶
Execute test and translate the outcome into a TestResult.
Times the call and maps exceptions to statuses: an
AssertionError becomes FAILED, any other exception becomes
ERROR.
Args: ctx: Context to run against.
Returns:
The outcome for this test, named after self.name or the
class name when no explicit name was set.
Source code in modeltest/core/base.py
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
ModelSuite(name='suite', tests=None)
¶
A collection of tests run together against a model + data.
Collect tests to run together against one model + dataset.
Args:
name: Label used in reports and JUnit XML.
tests: Initial tests; more can be added with
add_test / add_tests.
Source code in modeltest/core/base.py
231 232 233 234 235 236 237 238 239 240 | |
add_test(test)
¶
Append a test to the suite. Returns self, for chaining.
Source code in modeltest/core/base.py
242 243 244 245 | |
add_tests(*tests)
¶
Append several tests at once. Returns self, for chaining.
Source code in modeltest/core/base.py
247 248 249 250 | |
run(model, X_val, y_val, X_train=None, y_train=None, **metadata)
¶
Run every test against a model and validation data.
Builds a single TestContext (with the shared prediction cache)
and passes it to all tests, so predictions are computed once.
Args:
model: The model under test (wrapped automatically).
X_val: Validation features (DataFrame or array).
y_val: Ground-truth labels for the validation set.
X_train: Optional training features — required by the
drift tests.
y_train: Optional training labels.
**metadata: Extra key/value pairs stored in the context, e.g.
model_name="fraud_rf".
Returns:
Aggregate outcome with one TestResult per test.
Source code in modeltest/core/base.py
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | |
SuiteResult(suite_name, results=list())
dataclass
¶
Aggregate outcome of running every test in a suite.
passed
property
¶
True when every test in the suite passed.
num_passed
property
¶
Count of PASSED tests.
num_failed
property
¶
Count of tests that did not pass (FAILED, ERROR or SKIPPED).
report(style='table')
¶
Render the suite outcome.
Args:
style: "table" (console), "json" (machine-readable) or
"junit" (XML for CI test reporters).
Returns: The rendered report as a string.
Source code in modeltest/core/base.py
314 315 316 317 318 319 320 321 322 323 324 325 326 | |
assert_metric(actual, expected, op, msg)
¶
Raise AssertionError when op(actual, expected) is not truthy.
Small helper for custom tests that express a check as a metric, a comparison and a message.
Args:
actual: Computed metric value.
expected: Reference value handed to op.
op: Comparison callable, e.g. operator.ge.
msg: Failure message used verbatim in the AssertionError.
Raises: AssertionError: If the comparison fails.
Source code in modeltest/core/base.py
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | |
modeltest.core.runner
¶
Test execution entry points.
run_test(test, ctx)
¶
Run a single test against a context.
Args: test: The test to execute. ctx: Context with model, data and the shared prediction cache.
Returns:
The test's TestResult.
Source code in modeltest/core/runner.py
8 9 10 11 12 13 14 15 16 17 18 | |
run_suite(suite, ctx)
¶
Run every test in a suite against one shared context.
Sharing the context is what makes prediction caching work across tests: the first prediction is computed and every later test predicting on the same data reuses it.
Args: suite: The suite to execute. ctx: The (single) context handed to every test.
Returns:
Aggregate outcome with one TestResult per test, in order.
Source code in modeltest/core/runner.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
modeltest.core.report
¶
Report rendering: console table, JSON, and JUnit XML (for CI/CD).
render_report(result, style='table')
¶
Render a SuiteResult in the requested style.
Args:
result: The suite outcome to render.
style: "table" (console, default), "json" or "junit".
Returns: The rendered report as a string.
Raises: ValueError: Via the JSON encoder path if the payload is not serializable (should not happen for standard results).
Source code in modeltest/core/report.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
to_json(result)
¶
Serialize a SuiteResult to a JSON string.
Includes the suite name, aggregate counts and one object per test with name, status, detail, duration and recorded metrics.
Args: result: The suite outcome to serialize.
Returns: Pretty-printed JSON (2-space indent).
Source code in modeltest/core/report.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
to_junit_xml(result)
¶
Serialize a SuiteResult to JUnit XML.
The output wraps everything in the standard <testsuites> element
expected by CI test reporters (GitHub Actions, Jenkins, GitLab...):
FAILED tests become <failure> nodes, ERROR tests <error>.
Args: result: The suite outcome to serialize.
Returns: The XML document as a string.
Source code in modeltest/core/report.py
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |