fiddler-client 2.3.0.dev2__py3-none-any.whl → 2.4.0.dev1__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.
Files changed (65) hide show
  1. fiddler/__init__.py +2 -0
  2. fiddler/_version.py +1 -1
  3. fiddler/api/alert_mixin.py +1 -1
  4. fiddler/api/api.py +2 -0
  5. fiddler/api/webhooks_mixin.py +9 -7
  6. fiddler/core_objects.py +98 -47
  7. fiddler/schemas/custom_features.py +25 -19
  8. fiddler3/constants/baseline.py +19 -0
  9. fiddler3/constants/common.py +12 -0
  10. fiddler3/constants/dataset.py +7 -0
  11. fiddler3/constants/model_deployment.py +15 -0
  12. fiddler3/constants/xai.py +11 -0
  13. fiddler3/entities/__init__.py +5 -1
  14. fiddler3/entities/base.py +22 -18
  15. fiddler3/entities/baseline.py +228 -0
  16. fiddler3/entities/dataset.py +149 -0
  17. fiddler3/entities/job.py +9 -8
  18. fiddler3/entities/model.py +160 -29
  19. fiddler3/entities/model_artifact.py +350 -0
  20. fiddler3/entities/model_deployment.py +112 -0
  21. fiddler3/entities/model_surrogate.py +92 -0
  22. fiddler3/entities/organization.py +38 -0
  23. fiddler3/entities/project.py +69 -8
  24. fiddler3/entities/user.py +45 -0
  25. fiddler3/entities/xai.py +309 -0
  26. fiddler3/libs/http_client.py +24 -13
  27. fiddler3/libs/json_encoder.py +12 -0
  28. fiddler3/schemas/__init__.py +4 -0
  29. fiddler3/schemas/baseline.py +37 -0
  30. fiddler3/schemas/custom_features.py +23 -18
  31. fiddler3/schemas/dataset.py +27 -0
  32. fiddler3/schemas/deployment_params.py +25 -0
  33. fiddler3/schemas/filter_query.py +54 -0
  34. fiddler3/schemas/job.py +2 -2
  35. fiddler3/schemas/model.py +9 -9
  36. fiddler3/schemas/model_artifact.py +6 -0
  37. fiddler3/schemas/model_deployment.py +26 -0
  38. fiddler3/schemas/organization.py +9 -1
  39. fiddler3/schemas/project.py +4 -4
  40. fiddler3/schemas/server_info.py +2 -2
  41. fiddler3/schemas/user.py +1 -1
  42. fiddler3/schemas/xai.py +32 -0
  43. fiddler3/tests/apis/test_baseline.py +292 -0
  44. fiddler3/tests/apis/test_dataset.py +173 -0
  45. fiddler3/tests/apis/test_mixin.py +77 -0
  46. fiddler3/tests/apis/test_model.py +102 -7
  47. fiddler3/tests/apis/test_model_artifact.py +175 -0
  48. fiddler3/tests/apis/test_model_deployment.py +98 -0
  49. fiddler3/tests/apis/test_model_surrogate.py +159 -0
  50. fiddler3/tests/apis/test_project.py +36 -20
  51. fiddler3/tests/apis/test_xai.py +690 -0
  52. fiddler3/tests/constants.py +10 -0
  53. fiddler3/tests/test_json_encoder.py +16 -0
  54. fiddler3/tests/test_logger.py +12 -0
  55. fiddler3/tests/test_utils.py +19 -0
  56. fiddler3/utils/__init__.py +1 -0
  57. fiddler3/utils/helpers.py +43 -0
  58. fiddler3/utils/logger.py +15 -0
  59. fiddler3/utils/validations.py +11 -0
  60. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/METADATA +7 -5
  61. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/RECORD +65 -33
  62. tests/fiddler/test_segments.py +227 -0
  63. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/LICENSE.txt +0 -0
  64. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/WHEEL +0 -0
  65. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,690 @@
1
+ import io
2
+ import os
3
+ import shutil
4
+ from collections import namedtuple
5
+
6
+ import pandas as pd
7
+ import responses
8
+
9
+ from fiddler3.entities.model import Model
10
+ from fiddler3.schemas.xai import DatasetDataSource, RowDataSource
11
+ from fiddler3.tests.constants import (
12
+ BASE_TEST_DIR,
13
+ DATASET_NAME,
14
+ MODEL_ID,
15
+ MODEL_NAME,
16
+ ORG_ID,
17
+ ORG_NAME,
18
+ OUTPUT_DIR,
19
+ PROJECT_ID,
20
+ PROJECT_NAME,
21
+ URL,
22
+ USER_EMAIL,
23
+ USER_ID,
24
+ USER_NAME,
25
+ )
26
+
27
+ MODEL_SCHEMA = {
28
+ 'columns': [
29
+ {
30
+ 'bins': [
31
+ 350.0,
32
+ 400.0,
33
+ 450.0,
34
+ 500.0,
35
+ 550.0,
36
+ 600.0,
37
+ 650.0,
38
+ 700.0,
39
+ 750.0,
40
+ 800.0,
41
+ 850.0,
42
+ ],
43
+ 'categories': None,
44
+ 'data_type': 'int',
45
+ 'id': 'creditscore',
46
+ 'max': 850,
47
+ 'min': 350,
48
+ 'n_dimensions': None,
49
+ 'name': 'CreditScore',
50
+ 'replace_with_nulls': None,
51
+ },
52
+ ],
53
+ 'schema_version': 1,
54
+ }
55
+ MODEL_SPEC = {
56
+ 'custom_features': [],
57
+ 'decisions': ['Decisions'],
58
+ 'inputs': [
59
+ 'CreditScore',
60
+ ],
61
+ 'metadata': [],
62
+ 'outputs': ['probability_churned'],
63
+ 'schema_version': 1,
64
+ 'targets': ['Churned'],
65
+ }
66
+ MODEL_API_RESPONSE_200 = {
67
+ 'data': {
68
+ 'id': MODEL_ID,
69
+ 'name': MODEL_NAME,
70
+ 'project': {
71
+ 'id': PROJECT_ID,
72
+ 'name': PROJECT_NAME,
73
+ },
74
+ 'organization': {
75
+ 'id': ORG_ID,
76
+ 'name': ORG_NAME,
77
+ },
78
+ 'input_type': 'structured',
79
+ 'task': 'binary_classification',
80
+ 'task_params': {
81
+ 'binary_classification_threshold': 0.5,
82
+ 'target_class_order': ['Not Churned', 'Churned'],
83
+ 'group_by': None,
84
+ 'top_k': None,
85
+ 'class_weights': None,
86
+ 'weighted_ref_histograms': None,
87
+ },
88
+ 'schema': MODEL_SCHEMA,
89
+ 'spec': MODEL_SPEC,
90
+ 'description': 'This model predicts whether customer stays or churns',
91
+ 'event_id_col': None,
92
+ 'event_ts_col': None,
93
+ 'event_ts_format': None,
94
+ 'xai_params': {
95
+ 'custom_explain_methods': [],
96
+ 'default_explain_method': None,
97
+ },
98
+ 'artifact_status': 'no_model',
99
+ 'artifact_files': [],
100
+ 'created_at': '2023-11-22 16:50:57.705784',
101
+ 'updated_at': '2023-11-22 16:50:57.705784',
102
+ 'created_by': {
103
+ 'id': USER_ID,
104
+ 'full_name': USER_NAME,
105
+ 'email': USER_EMAIL,
106
+ },
107
+ 'updated_by': {
108
+ 'id': USER_ID,
109
+ 'full_name': USER_NAME,
110
+ 'email': USER_EMAIL,
111
+ },
112
+ 'input_cols': [
113
+ MODEL_SCHEMA['columns'][0],
114
+ MODEL_SCHEMA['columns'][0],
115
+ ],
116
+ 'output_cols': [MODEL_SCHEMA['columns'][0]],
117
+ 'target_cols': [MODEL_SCHEMA['columns'][0]],
118
+ 'metadata_cols': [],
119
+ 'decision_cols': [MODEL_SCHEMA['columns'][0]],
120
+ 'is_binary_ranking_model': False,
121
+ },
122
+ }
123
+
124
+ EXPLAIN_RESPONSE_200 = {
125
+ 'data': {
126
+ 'explanation_type': 'FIDDLER_SHAP',
127
+ 'num_permutations': 50,
128
+ 'ci_level': 0.95,
129
+ 'explanations': {
130
+ 'probability_churned': {
131
+ 'model_prediction': 0.40507614012286625,
132
+ 'baseline_prediction': 0.19293562908483303,
133
+ 'GEM': {
134
+ 'type': 'container',
135
+ 'contents': [
136
+ {
137
+ 'type': 'simple',
138
+ 'feature-name': 'CreditScore',
139
+ 'value': 619,
140
+ 'attribution': -0.022117800470630538,
141
+ 'attribution-uncertainty': 0.006245936205277383,
142
+ },
143
+ {
144
+ 'type': 'simple',
145
+ 'feature-name': 'Geography',
146
+ 'value': 'France',
147
+ 'attribution': 0.028808698749482956,
148
+ 'attribution-uncertainty': 0.008490776240161464,
149
+ },
150
+ {
151
+ 'type': 'simple',
152
+ 'feature-name': 'Gender',
153
+ 'value': 'Female',
154
+ 'attribution': 0.059352095878178614,
155
+ 'attribution-uncertainty': 0.010825591198269912,
156
+ },
157
+ {
158
+ 'type': 'simple',
159
+ 'feature-name': 'Age',
160
+ 'value': 42,
161
+ 'attribution': 0.04663932271153231,
162
+ 'attribution-uncertainty': 0.026679728117630943,
163
+ },
164
+ {
165
+ 'type': 'simple',
166
+ 'feature-name': 'Tenure',
167
+ 'value': 2,
168
+ 'attribution': 0.012244800190215574,
169
+ 'attribution-uncertainty': 0.006979182051724819,
170
+ },
171
+ {
172
+ 'type': 'simple',
173
+ 'feature-name': 'Balance',
174
+ 'value': 0.0,
175
+ 'attribution': 0.08161626352219709,
176
+ 'attribution-uncertainty': 0.017052188444913206,
177
+ },
178
+ {
179
+ 'type': 'simple',
180
+ 'feature-name': 'NumOfProducts',
181
+ 'value': 1,
182
+ 'attribution': 0.038190793675380155,
183
+ 'attribution-uncertainty': 0.0582498509252494,
184
+ },
185
+ {
186
+ 'type': 'simple',
187
+ 'feature-name': 'HasCrCard',
188
+ 'value': 'Yes',
189
+ 'attribution': 0.00654585439939201,
190
+ 'attribution-uncertainty': 0.004515983491581958,
191
+ },
192
+ {
193
+ 'type': 'simple',
194
+ 'feature-name': 'IsActiveMember',
195
+ 'value': 'Yes',
196
+ 'attribution': -0.05122940826721414,
197
+ 'attribution-uncertainty': 0.013359099976724447,
198
+ },
199
+ {
200
+ 'type': 'simple',
201
+ 'feature-name': 'EstimatedSalary',
202
+ 'value': 101348.88,
203
+ 'attribution': 0.012089890649499193,
204
+ 'attribution-uncertainty': 0.004951759795660022,
205
+ },
206
+ ],
207
+ 'attribution': 0.21214051103803322,
208
+ },
209
+ },
210
+ },
211
+ 'num_refs': 30,
212
+ },
213
+ 'api_version': '3.0',
214
+ 'kind': 'NORMAL',
215
+ }
216
+
217
+ FAIRNESS_RESPONSE_200 = {
218
+ 'data': {
219
+ 'protected_attributes': ['Gender'],
220
+ 'label_distribution': {
221
+ 'columns': ['Gender', 'data_label', 'count'],
222
+ 'labels': [
223
+ ['Female', 'Churned', 79],
224
+ ['Female', 'Not Churned', 377],
225
+ ['Male', 'Churned', 39],
226
+ ['Male', 'Not Churned', 505],
227
+ ],
228
+ },
229
+ 'model_outcomes': {
230
+ 'columns': ['Gender', 'model_outcome', 'count'],
231
+ 'outcomes': [
232
+ ['Female', 'Churned', 51],
233
+ ['Female', 'Not Churned', 405],
234
+ ['Male', 'Churned', 28],
235
+ ['Male', 'Not Churned', 516],
236
+ ],
237
+ },
238
+ 'technical_metrics': {
239
+ 'columns': [
240
+ 'Gender',
241
+ 'true_positive_rate',
242
+ 'false_positive_rate',
243
+ 'true_negative_rate',
244
+ 'false_negative_rate',
245
+ 'false_omission_rate',
246
+ 'false_discovery_rate',
247
+ ],
248
+ 'values': [
249
+ [
250
+ 'Female',
251
+ 0.569620253164557,
252
+ 0.015915119363395226,
253
+ 0.9840848806366048,
254
+ 0.43037974683544306,
255
+ 0.08395061728395062,
256
+ 0.11764705882352941,
257
+ ],
258
+ [
259
+ 'Male',
260
+ 0.5897435897435898,
261
+ 0.009900990099009901,
262
+ 0.9900990099009901,
263
+ 0.41025641025641024,
264
+ 0.031007751937984496,
265
+ 0.17857142857142858,
266
+ ],
267
+ ],
268
+ },
269
+ 'fairness_metrics': {
270
+ 'demographic_parity': {
271
+ 'index': ['dp'],
272
+ 'columns': ['Female', 'Male'],
273
+ 'data': [[0.1118421052631579, 0.051470588235294115]],
274
+ 'ratio': 0.4602076124567474,
275
+ },
276
+ 'equal_opportunity': {
277
+ 'index': ['tpr'],
278
+ 'columns': ['Female', 'Male'],
279
+ 'data': [[0.569620253164557, 0.5897435897435898]],
280
+ 'ratio': 0.9658778205833792,
281
+ },
282
+ 'group_benefit_equality': {
283
+ 'index': ['group_benefit'],
284
+ 'columns': ['Female', 'Male'],
285
+ 'data': [[0.6455696202531646, 0.717948717948718]],
286
+ 'ratio': 0.8991862567811935,
287
+ },
288
+ 'disparate_impact': {
289
+ 'pairs': [
290
+ {
291
+ 'reference': ['Female'],
292
+ 'groups': [['Male']],
293
+ 'values': [0.4602076124567474],
294
+ },
295
+ {
296
+ 'reference': ['Male'],
297
+ 'groups': [['Female']],
298
+ 'values': [0.4602076124567474],
299
+ },
300
+ ],
301
+ 'absolute_min': {
302
+ 'groups': [['Female'], ['Male']],
303
+ 'value': 0.4602076124567474,
304
+ },
305
+ },
306
+ },
307
+ 'model_task': 'BINARY_CLASSIFICATION',
308
+ 'total_samples': 1000,
309
+ 'valid_samples': 1000,
310
+ },
311
+ 'api_version': '3.0',
312
+ 'kind': 'NORMAL',
313
+ }
314
+
315
+ FETCH_SLICE_RESPONSE_200 = {
316
+ 'data': {
317
+ 'metadata': {
318
+ 'query': "SELECT * FROM test_bank_churn.bank_churn WHERE geography='France' order by balance desc LIMIT 2",
319
+ 'is_slice': True,
320
+ 'columns': ['Age'],
321
+ 'dtypes': ['int'],
322
+ 'model': {
323
+ 'id': '36bc3613-49d5-46b5-a0e0-a45c3aa4a9d9',
324
+ 'name': 'bank_churn',
325
+ },
326
+ 'env': {
327
+ 'id': '86e59334-2b86-4726-a970-6900db46e437',
328
+ 'type': 'PRE_PRODUCTION',
329
+ 'name': 'test_bank_churn',
330
+ },
331
+ },
332
+ 'rows': [[57], [37]],
333
+ },
334
+ 'api_version': '3.0',
335
+ 'kind': 'NORMAL',
336
+ }
337
+
338
+ MUTUAL_INFO_RESPONSE_200 = {
339
+ 'data': {
340
+ 'CreditScore': 0.009774993816146854,
341
+ 'Geography': 1.0387361759590092,
342
+ 'Gender': 0.000345600896640319,
343
+ 'Age': 0.006747713128151839,
344
+ 'Tenure': 0.0017159873190972647,
345
+ 'Balance': 0.14278016623398132,
346
+ 'NumOfProducts': 0.002155101383831244,
347
+ 'HasCrCard': 0.00011152799557884174,
348
+ 'IsActiveMember': 0.00026523254634630566,
349
+ 'EstimatedSalary': 0.010603971349228138,
350
+ 'probability_churned': 0.06073798415644517,
351
+ 'Decisions': 2.3682864881247045e-05,
352
+ 'Churned': 0.014017045772466472,
353
+ },
354
+ 'api_version': '3.0',
355
+ 'kind': 'NORMAL',
356
+ }
357
+
358
+ PREDICT_RESPONSE_200 = {
359
+ 'data': {'predictions': [{'predicted_quality': 5.759617514660622}]},
360
+ 'api_version': '3.0',
361
+ 'kind': 'NORMAL',
362
+ }
363
+
364
+ FEATURE_IMPORTANCE_RESPONSE_200 = {
365
+ 'data': {
366
+ 'loss': 'pointwise_logloss',
367
+ 'num_refs': 10000,
368
+ 'ci_level': 0.5,
369
+ 'mean_loss': 0.35653354054994635,
370
+ 'mean_loss_ci': 0.09459192835065221,
371
+ 'feature_names': [
372
+ 'CreditScore',
373
+ 'Geography',
374
+ 'Gender',
375
+ 'Age',
376
+ 'Tenure',
377
+ 'Balance',
378
+ 'NumOfProducts',
379
+ 'HasCrCard',
380
+ 'IsActiveMember',
381
+ 'EstimatedSalary',
382
+ ],
383
+ 'mean_loss_increase_importance': [
384
+ 0.004429064308612665,
385
+ 0.11303687040447762,
386
+ 0.010247568997879158,
387
+ 0.20021169408760484,
388
+ 0.020512200372182397,
389
+ 0.36803439130037513,
390
+ 0.2339702870224178,
391
+ 0.0014671647143862244,
392
+ 0.022758435725508515,
393
+ 0.011785520720929346,
394
+ ],
395
+ 'random_sample_ci': [
396
+ 0.00021145873961269672,
397
+ 0.0012444603359610608,
398
+ 0.00022339657233601845,
399
+ 0.0016025718376113422,
400
+ 0.00020151632282746737,
401
+ 0.0018154124659677064,
402
+ 0.0021341170223544335,
403
+ 0.00016283332959968953,
404
+ 0.0010258365777659855,
405
+ 0.0002324089593535596,
406
+ ],
407
+ 'fixed_sample_ci': [
408
+ 0.00018964651570488745,
409
+ 0.0010810129244220677,
410
+ 0.0001612062857999329,
411
+ 0.001333218784229577,
412
+ 0.000139368878515909,
413
+ 0.001191577806041505,
414
+ 0.0014415377334894384,
415
+ 8.741009867015967e-05,
416
+ 0.0007286815550017811,
417
+ 0.00019660620632828166,
418
+ ],
419
+ 'total_input_samples': 3,
420
+ 'valid_input_samples': 3,
421
+ 'model_task': 'BINARY_CLASSIFICATION',
422
+ 'model_input_type': 'TABULAR',
423
+ 'env_id': 'a6385884-4970-4eeb-b8cc-36ce9746cd5e',
424
+ 'env_name': DATASET_NAME,
425
+ 'created_at': '2023-11-22 16:50:57.705784',
426
+ },
427
+ 'api_version': '3.0',
428
+ 'kind': 'NORMAL',
429
+ }
430
+
431
+ FEATURE_IMPACT_RESPONSE_200 = {
432
+ 'data': {
433
+ 'num_inputs': 3,
434
+ 'num_refs': 10000,
435
+ 'ci_level': 0.5,
436
+ 'mean_prediction': 0.08983428988388353,
437
+ 'mean_prediction_ci': 0.006687591607821416,
438
+ 'feature_names': [
439
+ 'CreditScore',
440
+ 'Geography',
441
+ 'Gender',
442
+ 'Age',
443
+ 'Tenure',
444
+ 'Balance',
445
+ 'NumOfProducts',
446
+ 'HasCrCard',
447
+ 'IsActiveMember',
448
+ 'EstimatedSalary',
449
+ ],
450
+ 'mean_abs_prediction_change_impact': [
451
+ 0.00712590582097325,
452
+ 0.04386081743167407,
453
+ 0.01618882705936992,
454
+ 0.09012170216686392,
455
+ 0.003203886657934025,
456
+ 0.034259594581994,
457
+ 0.03950092221577272,
458
+ 0.0008308543417424118,
459
+ 0.09500517056814688,
460
+ 0.015902298170793795,
461
+ ],
462
+ 'random_sample_ci': [
463
+ 9.460265530465104e-05,
464
+ 0.0004967738708175746,
465
+ 0.0001390532937646932,
466
+ 0.001011710786484173,
467
+ 3.2151564756512305e-05,
468
+ 0.0003379320087881252,
469
+ 0.0007824117094712736,
470
+ 6.632377333582839e-06,
471
+ 0.001290117285928614,
472
+ 0.0001246149963496527,
473
+ ],
474
+ 'fixed_sample_ci': [
475
+ 9.387290704313362e-05,
476
+ 0.00047072988314235967,
477
+ 0.00011810560126585543,
478
+ 0.0009869435854980898,
479
+ 2.6313946023718767e-05,
480
+ 0.0003171540654523467,
481
+ 0.0007768114901140053,
482
+ 5.596843413373775e-06,
483
+ 0.001029967633853864,
484
+ 0.00011703590760866858,
485
+ ],
486
+ 'model_task': 'BINARY_CLASSIFICATION',
487
+ 'model_input_type': 'TABULAR',
488
+ 'env_id': 'a6385884-4970-4eeb-b8cc-36ce9746cd5e',
489
+ 'env_name': DATASET_NAME,
490
+ 'created_at': '2023-11-22 16:50:57.705784',
491
+ },
492
+ 'api_version': '3.0',
493
+ 'kind': 'NORMAL',
494
+ }
495
+
496
+
497
+ @responses.activate
498
+ def test_explain() -> None:
499
+ responses.get(
500
+ url=f'{URL}/v3/models/{MODEL_ID}',
501
+ json=MODEL_API_RESPONSE_200,
502
+ )
503
+ model = Model.get(id_=MODEL_ID)
504
+
505
+ responses.post(
506
+ url=f'{URL}/v3/explain',
507
+ json=EXPLAIN_RESPONSE_200,
508
+ )
509
+ explain_result = model.explain(
510
+ input_data_source=RowDataSource(
511
+ row={
512
+ 'CreditScore': 619,
513
+ 'Geography': 'France',
514
+ 'Gender': 'Female',
515
+ 'Age': 42,
516
+ 'Tenure': 2,
517
+ 'Balance': 0.0,
518
+ 'NumOfProducts': 1,
519
+ 'HasCrCard': 'Yes',
520
+ 'IsActiveMember': 'Yes',
521
+ 'EstimatedSalary': 101348.88,
522
+ },
523
+ ),
524
+ ref_data_source=DatasetDataSource(
525
+ env_type='PRODUCTION',
526
+ ),
527
+ )
528
+ assert explain_result == namedtuple('Explain', EXPLAIN_RESPONSE_200['data'])(
529
+ **EXPLAIN_RESPONSE_200['data']
530
+ )
531
+
532
+
533
+ @responses.activate
534
+ def test_fairness() -> None:
535
+ responses.get(
536
+ url=f'{URL}/v3/models/{MODEL_ID}',
537
+ json=MODEL_API_RESPONSE_200,
538
+ )
539
+ model = Model.get(id_=MODEL_ID)
540
+
541
+ responses.post(
542
+ url=f'{URL}/v3/analytics/fairness',
543
+ json=FAIRNESS_RESPONSE_200,
544
+ )
545
+ fairness = model.get_fairness(
546
+ data_source=DatasetDataSource(
547
+ env_type='PRODUCTION',
548
+ ),
549
+ protected_features=['Gender'],
550
+ positive_outcome='Churned',
551
+ )
552
+ assert fairness == namedtuple('Fairness', FAIRNESS_RESPONSE_200['data'])(
553
+ **FAIRNESS_RESPONSE_200['data']
554
+ )
555
+
556
+
557
+ @responses.activate
558
+ def test_get_slice() -> None:
559
+ responses.get(
560
+ url=f'{URL}/v3/models/{MODEL_ID}',
561
+ json=MODEL_API_RESPONSE_200,
562
+ )
563
+ model = Model.get(id_=MODEL_ID)
564
+
565
+ responses.post(
566
+ url=f'{URL}/v3/slice-query/fetch',
567
+ json=FETCH_SLICE_RESPONSE_200,
568
+ )
569
+
570
+ slice_df = model.get_slice(
571
+ query="SELECT * FROM test_bank_churn.bank_churn WHERE geography='France' order by balance desc LIMIT 3",
572
+ columns=['Age'],
573
+ max_rows=2,
574
+ )
575
+ expected_df = pd.DataFrame({'Age': [57, 37]})
576
+ pd.testing.assert_frame_equal(expected_df, slice_df)
577
+
578
+
579
+ @responses.activate
580
+ def test_slice_download() -> None:
581
+ responses.get(
582
+ url=f'{URL}/v3/models/{MODEL_ID}',
583
+ json=MODEL_API_RESPONSE_200,
584
+ )
585
+ model = Model.get(id_=MODEL_ID)
586
+
587
+ parquet_path = os.path.join(OUTPUT_DIR, 'test_slice_download.parquet')
588
+ parquet_output = os.path.join(BASE_TEST_DIR, 'slice_test_dir')
589
+ with open(parquet_path, 'rb') as parquet_file:
590
+ data = io.BufferedReader(parquet_file)
591
+ responses.post(
592
+ url=f'{URL}/v3/slice-query/download',
593
+ body=data,
594
+ )
595
+ expected_df = pd.DataFrame({'Age': [38, 57, 42]})
596
+ model.download_slice(
597
+ output_dir=parquet_output,
598
+ query='SELECT * FROM test_bank_churn.bank_churn WHERE age>=20 order by balance desc',
599
+ columns=['Age'],
600
+ max_rows=3,
601
+ )
602
+ slice_df = pd.read_parquet(parquet_path)
603
+ pd.testing.assert_frame_equal(expected_df, slice_df)
604
+ shutil.rmtree(str(parquet_output))
605
+
606
+
607
+ @responses.activate
608
+ def test_mutual_info() -> None:
609
+ responses.get(
610
+ url=f'{URL}/v3/models/{MODEL_ID}',
611
+ json=MODEL_API_RESPONSE_200,
612
+ )
613
+ model = Model.get(id_=MODEL_ID)
614
+
615
+ responses.post(
616
+ url=f'{URL}/v3/analytics/mutual-info',
617
+ json=MUTUAL_INFO_RESPONSE_200,
618
+ )
619
+ mutual_info = model.get_mutual_info(
620
+ query=f'select * from {DATASET_NAME}.{MODEL_NAME}',
621
+ column_name='Geography',
622
+ )
623
+ assert mutual_info == MUTUAL_INFO_RESPONSE_200['data']
624
+
625
+
626
+ @responses.activate
627
+ def test_predict() -> None:
628
+ responses.get(
629
+ url=f'{URL}/v3/models/{MODEL_ID}',
630
+ json=MODEL_API_RESPONSE_200,
631
+ )
632
+ model = Model.get(id_=MODEL_ID)
633
+
634
+ responses.post(
635
+ url=f'{URL}/v3/predict',
636
+ json=PREDICT_RESPONSE_200,
637
+ )
638
+ data = {
639
+ 'row_id': 1109,
640
+ 'fixed acidity': 10.8,
641
+ 'volatile acidity': 0.47,
642
+ 'citric acid': 0.43,
643
+ 'residual sugar': 2.1,
644
+ 'chlorides': 0.171,
645
+ 'free sulfur dioxide': 27.0,
646
+ 'total sulfur dioxide': 66.0,
647
+ 'density': 0.9982,
648
+ 'pH': 3.17,
649
+ 'sulphates': 0.76,
650
+ 'alcohol': 10.8,
651
+ }
652
+ df = pd.DataFrame(data, index=data.keys())
653
+ predictions = model.predict(df=df)
654
+
655
+ expected_result = pd.DataFrame(PREDICT_RESPONSE_200['data']['predictions'])
656
+ pd.testing.assert_frame_equal(predictions, expected_result)
657
+
658
+
659
+ @responses.activate
660
+ def test_get_feature_importance() -> None:
661
+ responses.get(
662
+ url=f'{URL}/v3/models/{MODEL_ID}',
663
+ json=MODEL_API_RESPONSE_200,
664
+ )
665
+ model = Model.get(id_=MODEL_ID)
666
+
667
+ responses.post(
668
+ url=f'{URL}/v3/analytics/feature-importance/precomputed',
669
+ json=FEATURE_IMPORTANCE_RESPONSE_200,
670
+ )
671
+ assert model.get_precomputed_feature_importance() == namedtuple(
672
+ 'FeatureImportance', FEATURE_IMPORTANCE_RESPONSE_200['data']
673
+ )(**FEATURE_IMPORTANCE_RESPONSE_200['data'])
674
+
675
+
676
+ @responses.activate
677
+ def test_get_feature_impact() -> None:
678
+ responses.get(
679
+ url=f'{URL}/v3/models/{MODEL_ID}',
680
+ json=MODEL_API_RESPONSE_200,
681
+ )
682
+ model = Model.get(id_=MODEL_ID)
683
+
684
+ responses.post(
685
+ url=f'{URL}/v3/analytics/feature-impact/precomputed',
686
+ json=FEATURE_IMPACT_RESPONSE_200,
687
+ )
688
+ assert model.get_precomputed_feature_impact() == namedtuple(
689
+ 'FeatureImpact', FEATURE_IMPACT_RESPONSE_200['data']
690
+ )(**FEATURE_IMPACT_RESPONSE_200['data'])
@@ -1,3 +1,6 @@
1
+ import os
2
+ from pathlib import Path
3
+
1
4
  URL = 'https://dev.fiddler.ai'
2
5
  TOKEN = 'footoken'
3
6
  ORG_ID = '5531bfd9-2ca2-4a7b-bb5a-136c8da09ca0'
@@ -12,3 +15,10 @@ USER_NAME = 'foo'
12
15
  USER_EMAIL = 'foo@fiddler.ai'
13
16
  JOB_ID = '9df70575-7ced-42fd-bb50-a0e4351d2c9d'
14
17
  JOB_NAME = f'Deleting model {MODEL_NAME}'
18
+ DATASET_ID = 'ba6ec4e4-7188-44c5-ba84-c2cb22b4bb00'
19
+ DATASET_NAME = 'dataset3'
20
+ BASELINE_ID = 'af05646f-0cef-4638-84c9-0d195df2575d'
21
+ BASELINE_NAME = 'test_baseline'
22
+ MODEL_DEPLOYMENT_ID = 'fc07562a-1a27-4f66-9154-732d3b14b98a'
23
+ BASE_TEST_DIR = f'{Path(__file__).resolve().parent}'
24
+ OUTPUT_DIR = os.path.join(BASE_TEST_DIR, 'artifact_test_dir')