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
fiddler3/schemas/model.py CHANGED
@@ -8,18 +8,18 @@ from fiddler3.schemas.base import BaseModel
8
8
  from fiddler3.schemas.model_schema import Column, ModelSchema
9
9
  from fiddler3.schemas.model_spec import ModelSpec
10
10
  from fiddler3.schemas.model_task_params import ModelTaskParams
11
- from fiddler3.schemas.organization import OrganizationCompact
12
- from fiddler3.schemas.project import ProjectCompact
13
- from fiddler3.schemas.user import UserCompact
11
+ from fiddler3.schemas.organization import OrganizationCompactResp
12
+ from fiddler3.schemas.project import ProjectCompactResp
13
+ from fiddler3.schemas.user import UserCompactResp
14
14
  from fiddler3.schemas.xai_params import XaiParams
15
15
 
16
16
 
17
- class ModelCompact(BaseModel):
17
+ class ModelCompactResp(BaseModel):
18
18
  id: UUID
19
19
  name: str
20
20
 
21
21
 
22
- class ModelResponse(BaseModel):
22
+ class ModelResp(BaseModel):
23
23
  id: UUID
24
24
  name: str
25
25
  input_type: str
@@ -36,10 +36,10 @@ class ModelResponse(BaseModel):
36
36
  artifact_files: List[Dict]
37
37
  created_at: datetime
38
38
  updated_at: datetime
39
- created_by: UserCompact
40
- updated_by: UserCompact
41
- organization: OrganizationCompact
42
- project: ProjectCompact
39
+ created_by: UserCompactResp
40
+ updated_by: UserCompactResp
41
+ organization: OrganizationCompactResp
42
+ project: ProjectCompactResp
43
43
  input_cols: List[Column]
44
44
  output_cols: List[Column]
45
45
  target_cols: List[Column]
@@ -0,0 +1,6 @@
1
+ from fiddler3.schemas.base import BaseModel
2
+
3
+
4
+ class ModelArtifactDeployMultiPartUploadResp(BaseModel):
5
+ part_number: int
6
+ etag: str
@@ -0,0 +1,26 @@
1
+ from datetime import datetime
2
+ from uuid import UUID
3
+
4
+ from fiddler3.schemas.base import BaseModel
5
+ from fiddler3.schemas.model import ModelCompactResp
6
+ from fiddler3.schemas.organization import OrganizationCompactResp
7
+ from fiddler3.schemas.project import ProjectCompactResp
8
+ from fiddler3.schemas.user import UserCompactResp
9
+
10
+
11
+ class ModelDeploymentResponse(BaseModel):
12
+ id: UUID
13
+ model: ModelCompactResp
14
+ project: ProjectCompactResp
15
+ organization: OrganizationCompactResp
16
+ artifact_type: str
17
+ deployment_type: str
18
+ active: bool
19
+ image_uri: str
20
+ replicas: int
21
+ cpu: int
22
+ memory: int
23
+ created_at: datetime
24
+ updated_at: datetime
25
+ created_by: UserCompactResp
26
+ updated_by: UserCompactResp
@@ -1,8 +1,16 @@
1
+ from datetime import datetime
1
2
  from uuid import UUID
2
3
 
3
4
  from fiddler3.schemas.base import BaseModel
4
5
 
5
6
 
6
- class OrganizationCompact(BaseModel):
7
+ class OrganizationCompactResp(BaseModel):
7
8
  id: UUID
8
9
  name: str
10
+
11
+
12
+ class OrganizationResp(BaseModel):
13
+ id: UUID
14
+ name: str
15
+ created_at: datetime
16
+ updated_at: datetime
@@ -2,18 +2,18 @@ from datetime import datetime
2
2
  from uuid import UUID
3
3
 
4
4
  from fiddler3.schemas.base import BaseModel
5
- from fiddler3.schemas.organization import OrganizationCompact
5
+ from fiddler3.schemas.organization import OrganizationCompactResp
6
6
 
7
7
 
8
- class ProjectCompact(BaseModel):
8
+ class ProjectCompactResp(BaseModel):
9
9
  id: UUID
10
10
  name: str
11
11
 
12
12
 
13
- class ProjectResponse(BaseModel):
13
+ class ProjectResp(BaseModel):
14
14
  id: UUID
15
15
  name: str
16
16
  created_at: datetime
17
17
  updated_at: datetime
18
18
 
19
- organization: OrganizationCompact
19
+ organization: OrganizationCompactResp
@@ -2,7 +2,7 @@ from typing import Dict, Generator
2
2
 
3
3
  from fiddler3.libs.semver import VersionInfo
4
4
  from fiddler3.schemas.base import BaseModel
5
- from fiddler3.schemas.organization import OrganizationCompact
5
+ from fiddler3.schemas.organization import OrganizationCompactResp
6
6
 
7
7
 
8
8
  class Version(VersionInfo):
@@ -15,4 +15,4 @@ class Version(VersionInfo):
15
15
  class ServerInfo(BaseModel):
16
16
  feature_flags: Dict
17
17
  server_version: Version
18
- organization: OrganizationCompact
18
+ organization: OrganizationCompactResp
fiddler3/schemas/user.py CHANGED
@@ -3,7 +3,7 @@ from uuid import UUID
3
3
  from pydantic import BaseModel
4
4
 
5
5
 
6
- class UserCompact(BaseModel):
6
+ class UserCompactResp(BaseModel):
7
7
  id: UUID
8
8
  full_name: str
9
9
  email: str
@@ -0,0 +1,32 @@
1
+ from typing import Dict, Optional, Union
2
+ from uuid import UUID
3
+
4
+ from pydantic import Field
5
+
6
+ from fiddler3.constants.dataset import EnvType
7
+ from fiddler3.schemas.base import BaseModel
8
+
9
+
10
+ class RowDataSource(BaseModel):
11
+ source_type = 'ROW'
12
+ row: Dict
13
+
14
+
15
+ class EventIdDataSource(BaseModel):
16
+ source_type = 'EVENT_ID'
17
+ event_id: str
18
+ env_id: Optional[Union[str, UUID]] = Field(alias='dataset_id')
19
+ env_type: EnvType
20
+
21
+
22
+ class DatasetDataSource(BaseModel):
23
+ source_type = 'ENVIRONMENT'
24
+ env_type: str
25
+ num_samples: Optional[int]
26
+ env_id: Optional[Union[str, UUID]] = Field(alias='dataset_id')
27
+
28
+
29
+ class SqlSliceQueryDataSource(BaseModel):
30
+ source_type = 'SQL_SLICE_QUERY'
31
+ query: str
32
+ num_samples: Optional[int]
@@ -0,0 +1,292 @@
1
+ from http import HTTPStatus
2
+ from uuid import UUID
3
+
4
+ import pytest
5
+ import responses
6
+ from responses import matchers
7
+
8
+ from fiddler3.constants.baseline import BaselineType
9
+ from fiddler3.entities.baseline import Baseline
10
+ from fiddler3.exceptions import Conflict, NotFound
11
+ from fiddler3.tests.constants import (
12
+ BASELINE_ID,
13
+ BASELINE_NAME,
14
+ DATASET_ID,
15
+ DATASET_NAME,
16
+ MODEL_ID,
17
+ MODEL_NAME,
18
+ ORG_ID,
19
+ ORG_NAME,
20
+ PROJECT_ID,
21
+ PROJECT_NAME,
22
+ URL,
23
+ )
24
+
25
+ API_RESPONSE_200 = {
26
+ 'data': {
27
+ 'id': BASELINE_ID,
28
+ 'name': BASELINE_NAME,
29
+ 'type': 'STATIC',
30
+ 'start_time': None,
31
+ 'end_time': None,
32
+ 'offset': None,
33
+ 'window_size': None,
34
+ 'row_count': 20000,
35
+ 'model': {
36
+ 'id': MODEL_ID,
37
+ 'name': MODEL_NAME,
38
+ },
39
+ 'project': {'id': PROJECT_ID, 'name': PROJECT_NAME},
40
+ 'organization': {
41
+ 'id': ORG_ID,
42
+ 'name': ORG_NAME,
43
+ },
44
+ 'environment': {
45
+ 'id': DATASET_ID,
46
+ 'name': DATASET_NAME,
47
+ 'type': 'PRE_PRODUCTION',
48
+ },
49
+ 'created_at': '2023-10-05T18:46:40.526590+00:00',
50
+ 'updated_at': '2023-10-05T18:46:40.526590+00:00',
51
+ },
52
+ 'api_version': '3.0',
53
+ 'kind': 'NORMAL',
54
+ }
55
+ API_RESPONSE_FROM_NAME = {
56
+ 'data': {
57
+ 'page_size': 100,
58
+ 'total': 1,
59
+ 'item_count': 1,
60
+ 'page_count': 1,
61
+ 'page_index': 1,
62
+ 'offset': 0,
63
+ 'items': [API_RESPONSE_200['data']],
64
+ }
65
+ }
66
+
67
+ LIST_API_RESPONSE = {
68
+ 'data': {
69
+ 'page_size': 100,
70
+ 'total': 2,
71
+ 'item_count': 2,
72
+ 'page_count': 1,
73
+ 'page_index': 1,
74
+ 'offset': 0,
75
+ 'items': [
76
+ API_RESPONSE_200['data'],
77
+ {
78
+ 'id': 'af05646f-0cef-4638-84c9-0d195df2575f',
79
+ 'name': 'test_baseline_2',
80
+ 'type': 'STATIC',
81
+ 'start_time': None,
82
+ 'end_time': None,
83
+ 'offset': None,
84
+ 'window_size': None,
85
+ 'row_count': 20000,
86
+ 'model': {
87
+ 'id': MODEL_ID,
88
+ 'name': MODEL_NAME,
89
+ },
90
+ 'project': {'id': PROJECT_ID, 'name': PROJECT_NAME},
91
+ 'organization': {
92
+ 'id': ORG_ID,
93
+ 'name': ORG_NAME,
94
+ },
95
+ 'environment': {
96
+ 'id': DATASET_ID,
97
+ 'name': DATASET_NAME,
98
+ 'type': 'PRE_PRODUCTION',
99
+ },
100
+ 'created_at': '2023-10-05T18:46:40.526590+00:00',
101
+ 'updated_at': '2023-10-05T18:46:40.526590+00:00',
102
+ },
103
+ ],
104
+ }
105
+ }
106
+
107
+ API_RESPONSE_404 = {
108
+ 'error': {
109
+ 'code': 404,
110
+ 'message': 'Baseline not found for the given identifier',
111
+ 'errors': [
112
+ {
113
+ 'reason': 'ObjectNotFound',
114
+ 'message': 'Baseline not found for the given identifier',
115
+ 'help': '',
116
+ }
117
+ ],
118
+ }
119
+ }
120
+
121
+ API_RESPONSE_409 = {
122
+ 'error': {
123
+ 'code': 409,
124
+ 'message': 'Baseline already exists',
125
+ 'errors': [
126
+ {
127
+ 'reason': 'Conflict',
128
+ 'message': 'Baseline already exists',
129
+ 'help': '',
130
+ }
131
+ ],
132
+ }
133
+ }
134
+
135
+
136
+ @responses.activate
137
+ def test_get_baseline_success() -> None:
138
+ responses.get(
139
+ url=f'{URL}/v3/baselines/{BASELINE_ID}',
140
+ json=API_RESPONSE_200,
141
+ )
142
+
143
+ baseline = Baseline.get(id_=BASELINE_ID)
144
+
145
+ assert isinstance(baseline, Baseline)
146
+
147
+
148
+ @responses.activate
149
+ def test_get_baseline_not_found() -> None:
150
+ responses.get(
151
+ url=f'{URL}/v3/baselines/{BASELINE_ID}',
152
+ json=API_RESPONSE_404,
153
+ status=HTTPStatus.NOT_FOUND,
154
+ )
155
+
156
+ with pytest.raises(NotFound):
157
+ Baseline.get(id_=BASELINE_ID)
158
+
159
+
160
+ @responses.activate
161
+ def test_baseline_from_name() -> None:
162
+ params = {
163
+ 'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "test_baseline"}, {"field": "project_name", "operator": "equal", "value": "bank_churn"}, {"field": "model_name", "operator": "equal", "value": "bank_churn"}]}'
164
+ }
165
+
166
+ responses.get(
167
+ url=f'{URL}/v3/baselines',
168
+ json=API_RESPONSE_FROM_NAME,
169
+ match=[matchers.query_param_matcher(params)],
170
+ )
171
+ baseline = Baseline.from_name(
172
+ name=BASELINE_NAME,
173
+ model_name=MODEL_NAME,
174
+ project_name=PROJECT_NAME,
175
+ )
176
+ assert isinstance(baseline, Baseline)
177
+
178
+
179
+ @responses.activate
180
+ def test_baseline_from_name_not_found() -> None:
181
+ resp = API_RESPONSE_FROM_NAME.copy()
182
+ resp['data']['total'] = 0
183
+ resp['data']['item_count'] = 0
184
+ resp['data']['items'] = []
185
+
186
+ params = {
187
+ 'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "test_baseline"}, {"field": "project_name", "operator": "equal", "value": "bank_churn"}, {"field": "model_name", "operator": "equal", "value": "bank_churn"}]}'
188
+ }
189
+
190
+ responses.get(
191
+ url=f'{URL}/v3/baselines',
192
+ json=resp,
193
+ match=[matchers.query_param_matcher(params)],
194
+ )
195
+ with pytest.raises(NotFound):
196
+ Baseline.from_name(
197
+ name=BASELINE_NAME,
198
+ model_name=MODEL_NAME,
199
+ project_name=PROJECT_NAME,
200
+ )
201
+
202
+
203
+ @responses.activate
204
+ def test_baseline_list_success() -> None:
205
+ responses.get(
206
+ url=f'{URL}/v3/baselines',
207
+ json=LIST_API_RESPONSE,
208
+ )
209
+ for baseline in Baseline.list():
210
+ assert isinstance(baseline, Baseline)
211
+
212
+
213
+ @responses.activate
214
+ def test_baseline_list_empty() -> None:
215
+ resp = API_RESPONSE_FROM_NAME.copy()
216
+ resp['data']['total'] = 0
217
+ resp['data']['item_count'] = 0
218
+ resp['data']['items'] = []
219
+
220
+ responses.get(
221
+ url=f'{URL}/v3/baselines',
222
+ json=resp,
223
+ )
224
+ assert len(list(Baseline.list())) == 0
225
+
226
+
227
+ @responses.activate
228
+ def test_add_baseline_success() -> None:
229
+ responses.post(
230
+ url=f'{URL}/v3/baselines',
231
+ json=API_RESPONSE_200,
232
+ )
233
+ baseline = Baseline(
234
+ name=BASELINE_NAME,
235
+ model_id=MODEL_ID,
236
+ environment='PRE_PRODUCTION',
237
+ dataset_id=DATASET_ID,
238
+ type_=BaselineType.STATIC,
239
+ ).create()
240
+
241
+ assert isinstance(baseline, Baseline)
242
+ assert baseline.id == UUID(BASELINE_ID)
243
+ assert baseline.name == BASELINE_NAME
244
+
245
+
246
+ @responses.activate
247
+ def test_add_baseline_conflict() -> None:
248
+ responses.post(
249
+ url=f'{URL}/v3/baselines', json=API_RESPONSE_409, status=HTTPStatus.CONFLICT
250
+ )
251
+
252
+ with pytest.raises(Conflict):
253
+ Baseline(
254
+ name=BASELINE_NAME,
255
+ model_id=MODEL_ID,
256
+ environment='PRE_PRODUCTION',
257
+ dataset_id=DATASET_ID,
258
+ type_=BaselineType.STATIC,
259
+ ).create()
260
+
261
+
262
+ @responses.activate
263
+ def test_delete_baseline() -> None:
264
+ responses.get(
265
+ url=f'{URL}/v3/baselines/{BASELINE_ID}',
266
+ json=API_RESPONSE_200,
267
+ )
268
+ baseline = Baseline.get(id_=BASELINE_ID)
269
+
270
+ responses.delete(
271
+ url=f'{URL}/v3/baselines/{BASELINE_ID}',
272
+ )
273
+
274
+ baseline.delete()
275
+
276
+
277
+ @responses.activate
278
+ def test_delete_baseline_not_found() -> None:
279
+ responses.get(
280
+ url=f'{URL}/v3/baselines/{BASELINE_ID}',
281
+ json=API_RESPONSE_200,
282
+ )
283
+ baseline = Baseline.get(id_=BASELINE_ID)
284
+
285
+ responses.delete(
286
+ url=f'{URL}/v3/baselines/{BASELINE_ID}',
287
+ json=API_RESPONSE_404,
288
+ status=HTTPStatus.NOT_FOUND,
289
+ )
290
+
291
+ with pytest.raises(NotFound):
292
+ baseline.delete()
@@ -0,0 +1,173 @@
1
+ from http import HTTPStatus
2
+
3
+ import pytest
4
+ import responses
5
+ from responses import matchers
6
+
7
+ from fiddler3.entities.dataset import Dataset
8
+ from fiddler3.exceptions import NotFound
9
+ from fiddler3.tests.constants import (
10
+ DATASET_ID,
11
+ DATASET_NAME,
12
+ MODEL_ID,
13
+ MODEL_NAME,
14
+ ORG_ID,
15
+ ORG_NAME,
16
+ PROJECT_ID,
17
+ PROJECT_NAME,
18
+ URL,
19
+ )
20
+
21
+ API_RESPONSE_200 = {
22
+ 'data': {
23
+ 'id': DATASET_ID,
24
+ 'name': DATASET_NAME,
25
+ 'type': 'PRE_PRODUCTION',
26
+ 'row_count': 10000,
27
+ 'model': {'id': MODEL_ID, 'name': MODEL_NAME},
28
+ 'project': {'id': PROJECT_ID, 'name': PROJECT_NAME},
29
+ 'organization': {'id': ORG_ID, 'name': ORG_NAME},
30
+ 'created_at': '2023-09-19T13:27:03.684345+00:00',
31
+ 'updated_at': '2023-09-19T13:27:03.684345+00:00',
32
+ },
33
+ 'api_version': '3.0',
34
+ 'kind': 'NORMAL',
35
+ }
36
+ API_RESPONSE_FROM_NAME = {
37
+ 'data': {
38
+ 'page_size': 100,
39
+ 'total': 1,
40
+ 'item_count': 1,
41
+ 'page_count': 1,
42
+ 'page_index': 1,
43
+ 'offset': 0,
44
+ 'items': [API_RESPONSE_200['data']],
45
+ }
46
+ }
47
+
48
+ LIST_API_RESPONSE = {
49
+ 'data': {
50
+ 'page_size': 100,
51
+ 'total': 2,
52
+ 'item_count': 2,
53
+ 'page_count': 1,
54
+ 'page_index': 1,
55
+ 'offset': 0,
56
+ 'items': [
57
+ API_RESPONSE_200['data'],
58
+ {
59
+ 'id': '2531bfd9-2ca2-4a7b-bb5a-136c8da09ca1',
60
+ 'name': 'dataset2',
61
+ 'type': 'PRE_PRODUCTION',
62
+ 'row_count': 10000,
63
+ 'model': {'id': MODEL_ID, 'name': MODEL_NAME},
64
+ 'project': {'id': PROJECT_ID, 'name': PROJECT_NAME},
65
+ 'organization': {'id': ORG_ID, 'name': ORG_NAME},
66
+ 'created_at': '2023-09-19T13:27:03.684345+00:00',
67
+ 'updated_at': '2023-09-19T13:27:03.684345+00:00',
68
+ },
69
+ ],
70
+ }
71
+ }
72
+
73
+ API_RESPONSE_404 = {
74
+ 'error': {
75
+ 'code': 404,
76
+ 'message': 'Environment not found for the given identifier',
77
+ 'errors': [
78
+ {
79
+ 'reason': 'ObjectNotFound',
80
+ 'message': 'Environment not found for the given identifier',
81
+ 'help': '',
82
+ }
83
+ ],
84
+ }
85
+ }
86
+
87
+
88
+ @responses.activate
89
+ def test_get_dataset_success() -> None:
90
+ responses.get(
91
+ url=f'{URL}/v3/environments/{DATASET_ID}',
92
+ json=API_RESPONSE_200,
93
+ )
94
+
95
+ dataset = Dataset.get(id_=DATASET_ID)
96
+ assert isinstance(dataset, Dataset)
97
+
98
+
99
+ @responses.activate
100
+ def test_get_dataset_not_found() -> None:
101
+ responses.get(
102
+ url=f'{URL}/v3/environments/{DATASET_ID}',
103
+ json=API_RESPONSE_404,
104
+ status=HTTPStatus.NOT_FOUND,
105
+ )
106
+
107
+ with pytest.raises(NotFound):
108
+ Dataset.get(id_=DATASET_ID)
109
+
110
+
111
+ @responses.activate
112
+ def test_dataset_from_name() -> None:
113
+ params = {
114
+ 'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "dataset3"}, {"field": "project_name", "operator": "equal", "value": "bank_churn"}, {"field": "model_name", "operator": "equal", "value": "bank_churn"}]}'
115
+ }
116
+ responses.get(
117
+ url=f'{URL}/v3/environments',
118
+ json=API_RESPONSE_FROM_NAME,
119
+ match=[matchers.query_param_matcher(params)],
120
+ )
121
+ dataset = Dataset.from_name(
122
+ name=DATASET_NAME,
123
+ model_name=MODEL_NAME,
124
+ project_name=PROJECT_NAME,
125
+ )
126
+ assert isinstance(dataset, Dataset)
127
+
128
+
129
+ @responses.activate
130
+ def test_dataset_from_name_not_found() -> None:
131
+ resp = API_RESPONSE_FROM_NAME.copy()
132
+ resp['data']['total'] = 0
133
+ resp['data']['item_count'] = 0
134
+ resp['data']['items'] = []
135
+
136
+ params = {
137
+ 'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "dataset3"}, {"field": "project_name", "operator": "equal", "value": "bank_churn"}, {"field": "model_name", "operator": "equal", "value": "bank_churn"}]}'
138
+ }
139
+ responses.get(
140
+ url=f'{URL}/v3/environments',
141
+ json=resp,
142
+ match=[matchers.query_param_matcher(params)],
143
+ )
144
+ with pytest.raises(NotFound):
145
+ Dataset.from_name(
146
+ name=DATASET_NAME,
147
+ model_name=MODEL_NAME,
148
+ project_name=PROJECT_NAME,
149
+ )
150
+
151
+
152
+ @responses.activate
153
+ def test_dataset_list_success() -> None:
154
+ responses.get(
155
+ url=f'{URL}/v3/environments',
156
+ json=LIST_API_RESPONSE,
157
+ )
158
+ for dataset in Dataset.list():
159
+ assert isinstance(dataset, Dataset)
160
+
161
+
162
+ @responses.activate
163
+ def test_dataset_list_empty() -> None:
164
+ resp = API_RESPONSE_FROM_NAME.copy()
165
+ resp['data']['total'] = 0
166
+ resp['data']['item_count'] = 0
167
+ resp['data']['items'] = []
168
+
169
+ responses.get(
170
+ url=f'{URL}/v3/environments',
171
+ json=resp,
172
+ )
173
+ assert len(list(Dataset.list())) == 0