fiddler-client 3.0.0.dev14__tar.gz → 3.1.0.dev2__tar.gz
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.
- {fiddler-client-3.0.0.dev14/fiddler_client.egg-info → fiddler-client-3.1.0.dev2}/PKG-INFO +1 -1
- fiddler-client-3.1.0.dev2/fiddler/VERSION +1 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/model.py +76 -19
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/custom_features.py +29 -29
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/model.py +2 -0
- fiddler-client-3.1.0.dev2/fiddler/schemas/model_spec.py +32 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_generate_model.py +6 -1
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_mixin.py +4 -1
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model.py +115 -6
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_xai.py +2 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/constants.py +1 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2/fiddler_client.egg-info}/PKG-INFO +1 -1
- fiddler-client-3.0.0.dev14/fiddler/VERSION +0 -1
- fiddler-client-3.0.0.dev14/fiddler/schemas/model_spec.py +0 -30
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/LICENSE.txt +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/MANIFEST.in +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/PUBLIC.md +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/README.md +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/configs.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/connection.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/alert_rule.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/baseline.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/common.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/dataset.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/events.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/job.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/model.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/model_deployment.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/xai.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/decorators.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/alert_record.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/alert_rule.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/base.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/baseline.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/custom_expression.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/dataset.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/events.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/file.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/job.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/model_artifact.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/model_deployment.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/organization.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/project.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/surrogate.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/user.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/webhook.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/xai.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/exceptions.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/libs/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/libs/http_client.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/libs/json_encoder.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/libs/semver.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/gem.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/keras_ig_helpers.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/project_attributions_helpers.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/template_model.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/alert_record.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/alert_rule.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/base.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/baseline.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/custom_expression.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/dataset.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/events.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/file.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/filter_query.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/job.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/model_deployment.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/model_schema.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/model_task_params.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/organization.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/project.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/response.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/server_info.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/user.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/webhook.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/xai.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/xai_params.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_alert_record.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_alert_rule.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_baseline.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_custom_metric.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_dataset.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_events.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_files.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_job.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model_artifact.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model_deployment.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model_surrogate.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_project.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_segment.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_webhook.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/conftest.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/test_connection.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/test_json_encoder.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/test_logger.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/test_utils.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/utils.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/utils/__init__.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/utils/helpers.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/utils/logger.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/utils/model_generator.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/utils/validations.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/utils/version.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/version.py +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/SOURCES.txt +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/dependency_links.txt +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/requires.txt +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/top_level.txt +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/setup.cfg +0 -0
- {fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.1.0.dev2
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import builtins
|
|
4
|
+
import copy
|
|
4
5
|
import typing
|
|
5
6
|
from dataclasses import dataclass
|
|
6
7
|
from datetime import datetime
|
|
@@ -52,6 +53,7 @@ class Model(
|
|
|
52
53
|
project_id: UUID | str,
|
|
53
54
|
schema: ModelSchema,
|
|
54
55
|
spec: ModelSpec,
|
|
56
|
+
version: str | None = None,
|
|
55
57
|
input_type: str = ModelInputType.TABULAR,
|
|
56
58
|
task: str = ModelTask.NOT_SET,
|
|
57
59
|
task_params: ModelTaskParams | None = None,
|
|
@@ -63,6 +65,7 @@ class Model(
|
|
|
63
65
|
) -> None:
|
|
64
66
|
"""Construct a model instance"""
|
|
65
67
|
self.name = name
|
|
68
|
+
self.version = version
|
|
66
69
|
self.project_id = project_id
|
|
67
70
|
self.schema = schema
|
|
68
71
|
self.input_type = input_type
|
|
@@ -101,6 +104,7 @@ class Model(
|
|
|
101
104
|
# Initialize
|
|
102
105
|
instance = cls(
|
|
103
106
|
name=resp_obj.name,
|
|
107
|
+
version=resp_obj.version,
|
|
104
108
|
schema=resp_obj.schema_,
|
|
105
109
|
spec=resp_obj.spec,
|
|
106
110
|
project_id=resp_obj.project.id,
|
|
@@ -141,6 +145,7 @@ class Model(
|
|
|
141
145
|
fields = [
|
|
142
146
|
'id',
|
|
143
147
|
'name',
|
|
148
|
+
'version',
|
|
144
149
|
'spec',
|
|
145
150
|
'input_type',
|
|
146
151
|
'task',
|
|
@@ -188,12 +193,20 @@ class Model(
|
|
|
188
193
|
|
|
189
194
|
@classmethod
|
|
190
195
|
@handle_api_error
|
|
191
|
-
def from_name(
|
|
196
|
+
def from_name(
|
|
197
|
+
cls,
|
|
198
|
+
name: str,
|
|
199
|
+
project_id: UUID | str,
|
|
200
|
+
version: str | None = None,
|
|
201
|
+
latest: bool = False,
|
|
202
|
+
) -> Model:
|
|
192
203
|
"""
|
|
193
204
|
Get the model instance from model name within a project.
|
|
194
205
|
|
|
195
206
|
:param name: Model name
|
|
196
207
|
:param project_id: Project identifier
|
|
208
|
+
:param version: Version name
|
|
209
|
+
:param latest: Whether to fetch the latest version of the model or first version
|
|
197
210
|
:return: Model instance
|
|
198
211
|
"""
|
|
199
212
|
_filter = QueryCondition(
|
|
@@ -207,8 +220,15 @@ class Model(
|
|
|
207
220
|
]
|
|
208
221
|
)
|
|
209
222
|
|
|
223
|
+
if version:
|
|
224
|
+
_filter.add_rule(
|
|
225
|
+
QueryRule(field='version', operator=OperatorType.EQUAL, value=version)
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
ordering = '-created_at' if latest else 'created_at'
|
|
210
229
|
response = cls._client().get(
|
|
211
|
-
url=cls._get_url(),
|
|
230
|
+
url=cls._get_url(),
|
|
231
|
+
params={'filter': _filter.json(), 'limit': 1, 'ordering': ordering},
|
|
212
232
|
)
|
|
213
233
|
|
|
214
234
|
if response.json()['data']['total'] == 0:
|
|
@@ -219,22 +239,27 @@ class Model(
|
|
|
219
239
|
@handle_api_error
|
|
220
240
|
def create(self) -> Model:
|
|
221
241
|
"""Create a new model."""
|
|
242
|
+
payload = {
|
|
243
|
+
'name': self.name,
|
|
244
|
+
'project_id': str(self.project_id),
|
|
245
|
+
'schema': self.schema.dict(),
|
|
246
|
+
'spec': self.spec.dict(),
|
|
247
|
+
'input_type': self.input_type,
|
|
248
|
+
'task': self.task,
|
|
249
|
+
'task_params': self.task_params.dict(),
|
|
250
|
+
'description': self.description,
|
|
251
|
+
'event_id_col': self.event_id_col,
|
|
252
|
+
'event_ts_col': self.event_ts_col,
|
|
253
|
+
'event_ts_format': self.event_ts_format,
|
|
254
|
+
'xai_params': self.xai_params.dict(),
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if self.version:
|
|
258
|
+
payload['version'] = self.version
|
|
259
|
+
|
|
222
260
|
response = self._client().post(
|
|
223
261
|
url=self._get_url(),
|
|
224
|
-
data=
|
|
225
|
-
'name': self.name,
|
|
226
|
-
'project_id': str(self.project_id),
|
|
227
|
-
'schema': self.schema.dict(),
|
|
228
|
-
'spec': self.spec.dict(),
|
|
229
|
-
'input_type': self.input_type,
|
|
230
|
-
'task': self.task,
|
|
231
|
-
'task_params': self.task_params.dict(),
|
|
232
|
-
'description': self.description,
|
|
233
|
-
'event_id_col': self.event_id_col,
|
|
234
|
-
'event_ts_col': self.event_ts_col,
|
|
235
|
-
'event_ts_format': self.event_ts_format,
|
|
236
|
-
'xai_params': self.xai_params.dict(),
|
|
237
|
-
},
|
|
262
|
+
data=payload,
|
|
238
263
|
)
|
|
239
264
|
self._refresh_from_response(response=response)
|
|
240
265
|
return self
|
|
@@ -243,6 +268,7 @@ class Model(
|
|
|
243
268
|
def update(self) -> None:
|
|
244
269
|
"""Update an existing model."""
|
|
245
270
|
body: dict[str, Any] = {
|
|
271
|
+
'version': self.version,
|
|
246
272
|
'xai_params': self.xai_params.dict(),
|
|
247
273
|
'description': self.description,
|
|
248
274
|
'event_id_col': self.event_id_col,
|
|
@@ -256,13 +282,13 @@ class Model(
|
|
|
256
282
|
@classmethod
|
|
257
283
|
@handle_api_error
|
|
258
284
|
def list(
|
|
259
|
-
cls,
|
|
260
|
-
project_id: UUID | str,
|
|
285
|
+
cls, project_id: UUID | str, name: str | None = None
|
|
261
286
|
) -> Iterator[ModelCompact]:
|
|
262
287
|
"""
|
|
263
288
|
Get a list of all models with the given filters
|
|
264
289
|
|
|
265
290
|
:param project_id: Project identifier
|
|
291
|
+
:param name: Model name, use this for listing all the versions of a model
|
|
266
292
|
:return: ModelCompact iterator
|
|
267
293
|
"""
|
|
268
294
|
_filter = QueryCondition(
|
|
@@ -273,11 +299,34 @@ class Model(
|
|
|
273
299
|
]
|
|
274
300
|
)
|
|
275
301
|
|
|
302
|
+
if name:
|
|
303
|
+
_filter.add_rule(
|
|
304
|
+
QueryRule(field='name', operator=OperatorType.EQUAL, value=name)
|
|
305
|
+
)
|
|
306
|
+
|
|
276
307
|
params = {'filter': _filter.json()}
|
|
277
308
|
|
|
278
309
|
for model in cls._paginate(url=cls._get_url(), params=params):
|
|
279
310
|
yield ModelCompact(id=model['id'], name=model['name'])
|
|
280
311
|
|
|
312
|
+
def duplicate(self, version: str | None = None) -> Model:
|
|
313
|
+
"""
|
|
314
|
+
Duplicate the model instance with the given version name.
|
|
315
|
+
|
|
316
|
+
This call will not save the model on server. After making changes to the model
|
|
317
|
+
instance call .create() to add the model version to Fiddler Platform.
|
|
318
|
+
|
|
319
|
+
:param version: Version name for the new instance
|
|
320
|
+
:return: Model instance
|
|
321
|
+
"""
|
|
322
|
+
self_copy = copy.deepcopy(self)
|
|
323
|
+
self_copy.id = None
|
|
324
|
+
|
|
325
|
+
if version:
|
|
326
|
+
self_copy.version = version
|
|
327
|
+
|
|
328
|
+
return self_copy
|
|
329
|
+
|
|
281
330
|
@property
|
|
282
331
|
def datasets(self) -> Iterator[Dataset]:
|
|
283
332
|
"""Fetch all the datasets of this model"""
|
|
@@ -316,6 +365,7 @@ class Model(
|
|
|
316
365
|
name: str,
|
|
317
366
|
project_id: UUID | str,
|
|
318
367
|
spec: ModelSpec | None = None,
|
|
368
|
+
version: str | None = None,
|
|
319
369
|
input_type: str = ModelInputType.TABULAR,
|
|
320
370
|
task: str = ModelTask.NOT_SET,
|
|
321
371
|
task_params: ModelTaskParams | None = None,
|
|
@@ -334,6 +384,7 @@ class Model(
|
|
|
334
384
|
:param name: Model name
|
|
335
385
|
:param project_id: Project identifier
|
|
336
386
|
:param spec: ModelSpec instance
|
|
387
|
+
:param version: Model version name
|
|
337
388
|
:param input_type: Model input task type
|
|
338
389
|
:param task: Model task like Regression, Binary classification etc.
|
|
339
390
|
:param task_params: Parameters based on the task type
|
|
@@ -354,6 +405,7 @@ class Model(
|
|
|
354
405
|
|
|
355
406
|
return Model(
|
|
356
407
|
name=name,
|
|
408
|
+
version=version,
|
|
357
409
|
schema=resp_obj.schema_,
|
|
358
410
|
spec=resp_obj.spec,
|
|
359
411
|
project_id=project_id,
|
|
@@ -496,6 +548,7 @@ class Model(
|
|
|
496
548
|
class ModelCompact:
|
|
497
549
|
id: UUID
|
|
498
550
|
name: str
|
|
551
|
+
version: str | None = None
|
|
499
552
|
|
|
500
553
|
def fetch(self) -> Model:
|
|
501
554
|
"""Fetch model instance"""
|
|
@@ -513,4 +566,8 @@ class ModelCompactMixin:
|
|
|
513
566
|
'response.'
|
|
514
567
|
)
|
|
515
568
|
|
|
516
|
-
return ModelCompact(
|
|
569
|
+
return ModelCompact(
|
|
570
|
+
id=response.model.id,
|
|
571
|
+
name=response.model.name,
|
|
572
|
+
version=response.model.version,
|
|
573
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Dict, List, Optional, Type, TypeVar
|
|
1
|
+
from typing import Any, Dict, List, Optional, Type, TypeVar, Literal
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, validator
|
|
4
4
|
|
|
@@ -10,18 +10,12 @@ CustomFeatureTypeVar = TypeVar('CustomFeatureTypeVar', bound='CustomFeature')
|
|
|
10
10
|
|
|
11
11
|
class CustomFeature(BaseModel):
|
|
12
12
|
name: str
|
|
13
|
-
type:
|
|
14
|
-
n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
|
|
15
|
-
centroids: Optional[List] = None
|
|
16
|
-
|
|
17
|
-
@validator('n_clusters')
|
|
18
|
-
def validate_n_clusters(cls, value: int) -> int: # noqa: N805
|
|
19
|
-
if value < 0:
|
|
20
|
-
raise ValueError('n_clusters must be greater than 0')
|
|
21
|
-
return value
|
|
13
|
+
type: Any
|
|
22
14
|
|
|
23
15
|
class Config:
|
|
24
16
|
allow_mutation = False
|
|
17
|
+
use_enum_values = True
|
|
18
|
+
discriminator = 'type'
|
|
25
19
|
|
|
26
20
|
@classmethod
|
|
27
21
|
def from_columns(
|
|
@@ -53,12 +47,13 @@ class CustomFeature(BaseModel):
|
|
|
53
47
|
return_dict: Dict[str, Any] = {
|
|
54
48
|
'name': self.name,
|
|
55
49
|
'type': self.type.value,
|
|
56
|
-
'n_clusters': self.n_clusters,
|
|
57
50
|
}
|
|
58
51
|
if isinstance(self, Multivariate):
|
|
59
52
|
return_dict['columns'] = self.columns
|
|
53
|
+
return_dict['n_clusters'] = self.n_clusters
|
|
60
54
|
elif isinstance(self, VectorFeature):
|
|
61
55
|
return_dict['column'] = self.column
|
|
56
|
+
return_dict['n_clusters'] = self.n_clusters
|
|
62
57
|
if isinstance(self, (ImageEmbedding, TextEmbedding)):
|
|
63
58
|
return_dict['source_column'] = self.source_column
|
|
64
59
|
if isinstance(self, TextEmbedding):
|
|
@@ -74,7 +69,9 @@ class CustomFeature(BaseModel):
|
|
|
74
69
|
|
|
75
70
|
|
|
76
71
|
class Multivariate(CustomFeature):
|
|
77
|
-
type:
|
|
72
|
+
type: Literal['FROM_COLUMNS'] = CustomFeatureType.FROM_COLUMNS.value
|
|
73
|
+
n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
|
|
74
|
+
centroids: Optional[List] = None
|
|
78
75
|
columns: List[str]
|
|
79
76
|
monitor_components: bool = False
|
|
80
77
|
|
|
@@ -84,24 +81,32 @@ class Multivariate(CustomFeature):
|
|
|
84
81
|
raise ValueError('Multivariate columns must be greater than 1')
|
|
85
82
|
return value
|
|
86
83
|
|
|
84
|
+
@validator('n_clusters')
|
|
85
|
+
def validate_n_clusters(cls, value: int) -> int: # noqa: N805
|
|
86
|
+
if value < 0:
|
|
87
|
+
raise ValueError('n_clusters must be greater than 0')
|
|
88
|
+
return value
|
|
89
|
+
|
|
87
90
|
|
|
88
91
|
class VectorFeature(CustomFeature):
|
|
89
|
-
type:
|
|
90
|
-
|
|
92
|
+
type: Literal['FROM_VECTOR'] = CustomFeatureType.FROM_VECTOR.value
|
|
93
|
+
n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
|
|
94
|
+
centroids: Optional[List] = None
|
|
91
95
|
column: str
|
|
92
96
|
|
|
97
|
+
@validator('n_clusters')
|
|
98
|
+
def validate_n_clusters(cls, value: int) -> int: # noqa: N805
|
|
99
|
+
if value < 0:
|
|
100
|
+
raise ValueError('n_clusters must be greater than 0')
|
|
101
|
+
return value
|
|
102
|
+
|
|
93
103
|
|
|
94
104
|
class TextEmbedding(VectorFeature):
|
|
95
|
-
type:
|
|
105
|
+
type: Literal['FROM_TEXT_EMBEDDING'] = CustomFeatureType.FROM_TEXT_EMBEDDING.value # type: ignore
|
|
106
|
+
source_column: str
|
|
96
107
|
n_tags: Optional[int] = DEFAULT_NUM_TAGS
|
|
97
108
|
tf_idf: Optional[Dict[str, List]] = None
|
|
98
109
|
|
|
99
|
-
@validator('source_column')
|
|
100
|
-
def validate_source_column(cls, value: str) -> str: # noqa: N805
|
|
101
|
-
if value is None:
|
|
102
|
-
raise ValueError('source_column must be specified')
|
|
103
|
-
return value
|
|
104
|
-
|
|
105
110
|
@validator('n_tags')
|
|
106
111
|
def validate_n_tags(cls, value: int) -> int: # noqa: N805
|
|
107
112
|
if value < 0:
|
|
@@ -110,13 +115,8 @@ class TextEmbedding(VectorFeature):
|
|
|
110
115
|
|
|
111
116
|
|
|
112
117
|
class ImageEmbedding(VectorFeature):
|
|
113
|
-
type:
|
|
114
|
-
|
|
115
|
-
@validator('source_column')
|
|
116
|
-
def validate_source_column(cls, value: str) -> str: # noqa: N805
|
|
117
|
-
if value is None:
|
|
118
|
-
raise ValueError('source_column must be specified')
|
|
119
|
-
return value
|
|
118
|
+
type: Literal['FROM_IMAGE_EMBEDDING'] = CustomFeatureType.FROM_IMAGE_EMBEDDING.value # type: ignore
|
|
119
|
+
source_column: str
|
|
120
120
|
|
|
121
121
|
|
|
122
122
|
class Enrichment(CustomFeature):
|
|
@@ -135,7 +135,7 @@ class Enrichment(CustomFeature):
|
|
|
135
135
|
"""
|
|
136
136
|
|
|
137
137
|
# Setting the feature type to ENRICHMENT
|
|
138
|
-
type:
|
|
138
|
+
type: Literal['ENRICHMENT'] = CustomFeatureType.ENRICHMENT.value
|
|
139
139
|
|
|
140
140
|
# List of input column names used to generate the enrichment
|
|
141
141
|
columns: List[str]
|
|
@@ -17,11 +17,13 @@ from fiddler.schemas.xai_params import XaiParams
|
|
|
17
17
|
class ModelCompactResp(BaseModel):
|
|
18
18
|
id: UUID
|
|
19
19
|
name: str
|
|
20
|
+
version: Optional[str]
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class ModelResp(BaseModel):
|
|
23
24
|
id: UUID
|
|
24
25
|
name: str
|
|
26
|
+
version: str
|
|
25
27
|
input_type: str
|
|
26
28
|
task: str
|
|
27
29
|
task_params: ModelTaskParams
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import List, Union
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
from fiddler.schemas.custom_features import Multivariate, VectorFeature, TextEmbedding, ImageEmbedding, Enrichment
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ModelSpec(BaseModel):
|
|
9
|
+
"""Model spec defines how model columns are used along with model task"""
|
|
10
|
+
|
|
11
|
+
schema_version: int = 1
|
|
12
|
+
"""Schema version"""
|
|
13
|
+
|
|
14
|
+
inputs: List[str] = Field(default_factory=list)
|
|
15
|
+
"""Feature columns"""
|
|
16
|
+
|
|
17
|
+
outputs: List[str] = Field(default_factory=list)
|
|
18
|
+
"""Prediction columns"""
|
|
19
|
+
|
|
20
|
+
targets: List[str] = Field(default_factory=list)
|
|
21
|
+
"""Label columns"""
|
|
22
|
+
|
|
23
|
+
decisions: List[str] = Field(default_factory=list)
|
|
24
|
+
"""Decisions columns"""
|
|
25
|
+
|
|
26
|
+
metadata: List[str] = Field(default_factory=list)
|
|
27
|
+
"""Metadata columns"""
|
|
28
|
+
|
|
29
|
+
custom_features: List[Union[Multivariate, VectorFeature, TextEmbedding, ImageEmbedding, Enrichment]] = Field(
|
|
30
|
+
default_factory=list
|
|
31
|
+
)
|
|
32
|
+
"""Custom feature definitions"""
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_generate_model.py
RENAMED
|
@@ -182,7 +182,12 @@ def test_generate_model_with_parquet_file() -> None:
|
|
|
182
182
|
|
|
183
183
|
DF.to_csv(temp_file.name, index=False)
|
|
184
184
|
|
|
185
|
+
version = 'v1.0'
|
|
185
186
|
model = Model.from_data(
|
|
186
|
-
source=temp_file.name,
|
|
187
|
+
source=temp_file.name,
|
|
188
|
+
name='model1',
|
|
189
|
+
version=version,
|
|
190
|
+
project_id=PROJECT_ID,
|
|
187
191
|
)
|
|
188
192
|
assert isinstance(model, Model)
|
|
193
|
+
assert model.version == version
|
|
@@ -20,6 +20,7 @@ from fiddler.tests.constants import (
|
|
|
20
20
|
DATASET_NAME,
|
|
21
21
|
MODEL_ID,
|
|
22
22
|
MODEL_NAME,
|
|
23
|
+
MODEL_VERSION,
|
|
23
24
|
PROJECT_ID,
|
|
24
25
|
PROJECT_NAME,
|
|
25
26
|
USER_EMAIL,
|
|
@@ -39,7 +40,9 @@ class DummyEntity(
|
|
|
39
40
|
def __init__(self) -> None:
|
|
40
41
|
self._resp = mock.MagicMock()
|
|
41
42
|
self._resp.project = ProjectCompactResp(id=PROJECT_ID, name=PROJECT_NAME)
|
|
42
|
-
self._resp.model = ModelCompactResp(
|
|
43
|
+
self._resp.model = ModelCompactResp(
|
|
44
|
+
id=MODEL_ID, name=MODEL_NAME, version=MODEL_VERSION
|
|
45
|
+
)
|
|
43
46
|
self._resp.dataset = DatasetCompactResp(
|
|
44
47
|
id=DATASET_ID, name=DATASET_NAME, type=EnvType.PRE_PRODUCTION
|
|
45
48
|
)
|
|
@@ -18,6 +18,7 @@ from fiddler.tests.constants import (
|
|
|
18
18
|
MODEL_DEPLOYMENT_ID,
|
|
19
19
|
MODEL_ID,
|
|
20
20
|
MODEL_NAME,
|
|
21
|
+
MODEL_VERSION,
|
|
21
22
|
ORG_ID,
|
|
22
23
|
ORG_NAME,
|
|
23
24
|
PROJECT_ID,
|
|
@@ -153,6 +154,7 @@ API_RESPONSE_200 = {
|
|
|
153
154
|
'data': {
|
|
154
155
|
'id': MODEL_ID,
|
|
155
156
|
'name': MODEL_NAME,
|
|
157
|
+
'version': MODEL_VERSION,
|
|
156
158
|
'project': {
|
|
157
159
|
'id': PROJECT_ID,
|
|
158
160
|
'name': PROJECT_NAME,
|
|
@@ -308,6 +310,7 @@ def test_add_model_success() -> None:
|
|
|
308
310
|
assert isinstance(model, Model)
|
|
309
311
|
assert model.id == UUID(MODEL_ID)
|
|
310
312
|
assert model.name == MODEL_NAME
|
|
313
|
+
assert model.version == MODEL_VERSION
|
|
311
314
|
|
|
312
315
|
|
|
313
316
|
@responses.activate
|
|
@@ -350,7 +353,9 @@ def test_get_model_not_found() -> None:
|
|
|
350
353
|
@responses.activate
|
|
351
354
|
def test_model_from_name_success() -> None:
|
|
352
355
|
params = {
|
|
353
|
-
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}'
|
|
356
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}',
|
|
357
|
+
'limit': 1,
|
|
358
|
+
'ordering': 'created_at',
|
|
354
359
|
}
|
|
355
360
|
responses.get(
|
|
356
361
|
url=f'{URL}/v3/models',
|
|
@@ -365,6 +370,48 @@ def test_model_from_name_success() -> None:
|
|
|
365
370
|
assert isinstance(model, Model)
|
|
366
371
|
|
|
367
372
|
|
|
373
|
+
@responses.activate
|
|
374
|
+
def test_model_from_name_with_version_success() -> None:
|
|
375
|
+
params = {
|
|
376
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}, {"field": "version", "operator": "equal", "value": "v1"}]}',
|
|
377
|
+
'limit': 1,
|
|
378
|
+
'ordering': 'created_at',
|
|
379
|
+
}
|
|
380
|
+
responses.get(
|
|
381
|
+
url=f'{URL}/v3/models',
|
|
382
|
+
json=API_RESPONSE_FROM_NAME,
|
|
383
|
+
match=[matchers.query_param_matcher(params)],
|
|
384
|
+
)
|
|
385
|
+
responses.get(
|
|
386
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
387
|
+
json=API_RESPONSE_200,
|
|
388
|
+
)
|
|
389
|
+
model = Model.from_name(
|
|
390
|
+
name=MODEL_NAME, version=MODEL_VERSION, project_id=PROJECT_ID
|
|
391
|
+
)
|
|
392
|
+
assert isinstance(model, Model)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
@responses.activate
|
|
396
|
+
def test_model_from_name_latest_success() -> None:
|
|
397
|
+
params = {
|
|
398
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}',
|
|
399
|
+
'limit': 1,
|
|
400
|
+
'ordering': '-created_at',
|
|
401
|
+
}
|
|
402
|
+
responses.get(
|
|
403
|
+
url=f'{URL}/v3/models',
|
|
404
|
+
json=API_RESPONSE_FROM_NAME,
|
|
405
|
+
match=[matchers.query_param_matcher(params)],
|
|
406
|
+
)
|
|
407
|
+
responses.get(
|
|
408
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
409
|
+
json=API_RESPONSE_200,
|
|
410
|
+
)
|
|
411
|
+
model = Model.from_name(name=MODEL_NAME, project_id=PROJECT_ID, latest=True)
|
|
412
|
+
assert isinstance(model, Model)
|
|
413
|
+
|
|
414
|
+
|
|
368
415
|
@responses.activate
|
|
369
416
|
def test_model_from_name_not_found() -> None:
|
|
370
417
|
resp = API_RESPONSE_FROM_NAME.copy()
|
|
@@ -373,7 +420,9 @@ def test_model_from_name_not_found() -> None:
|
|
|
373
420
|
resp['data']['items'] = []
|
|
374
421
|
|
|
375
422
|
params = {
|
|
376
|
-
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}'
|
|
423
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}',
|
|
424
|
+
'limit': 1,
|
|
425
|
+
'ordering': 'created_at',
|
|
377
426
|
}
|
|
378
427
|
responses.get(
|
|
379
428
|
url=f'{URL}/v3/models',
|
|
@@ -385,9 +434,35 @@ def test_model_from_name_not_found() -> None:
|
|
|
385
434
|
Model.from_name(name=MODEL_NAME, project_id=PROJECT_ID)
|
|
386
435
|
|
|
387
436
|
|
|
437
|
+
@responses.activate
|
|
438
|
+
def test_model_from_name_with_version_not_found() -> None:
|
|
439
|
+
resp = API_RESPONSE_FROM_NAME.copy()
|
|
440
|
+
resp['data']['total'] = 0
|
|
441
|
+
resp['data']['item_count'] = 0
|
|
442
|
+
resp['data']['items'] = []
|
|
443
|
+
|
|
444
|
+
params = {
|
|
445
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "bank_churn"}, {"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}, {"field": "version", "operator": "equal", "value": "v1"}]}',
|
|
446
|
+
'limit': 1,
|
|
447
|
+
'ordering': 'created_at',
|
|
448
|
+
}
|
|
449
|
+
responses.get(
|
|
450
|
+
url=f'{URL}/v3/models',
|
|
451
|
+
json=resp,
|
|
452
|
+
match=[matchers.query_param_matcher(params)],
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
with pytest.raises(NotFound):
|
|
456
|
+
Model.from_name(name=MODEL_NAME, version=MODEL_VERSION, project_id=PROJECT_ID)
|
|
457
|
+
|
|
458
|
+
|
|
388
459
|
@responses.activate
|
|
389
460
|
def test_model_list_success() -> None:
|
|
390
|
-
params = {
|
|
461
|
+
params = {
|
|
462
|
+
'filter': '{"condition": "AND", "rules": [{"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}',
|
|
463
|
+
'limit': 50,
|
|
464
|
+
'offset': 0,
|
|
465
|
+
}
|
|
391
466
|
responses.get(
|
|
392
467
|
url=f'{URL}/v3/models',
|
|
393
468
|
json=LIST_API_RESPONSE,
|
|
@@ -399,9 +474,9 @@ def test_model_list_success() -> None:
|
|
|
399
474
|
|
|
400
475
|
|
|
401
476
|
@responses.activate
|
|
402
|
-
def
|
|
477
|
+
def test_model_list_with_name() -> None:
|
|
403
478
|
params = {
|
|
404
|
-
'filter': '{"condition": "AND", "rules": [{"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}]}',
|
|
479
|
+
'filter': '{"condition": "AND", "rules": [{"field": "project_id", "operator": "equal", "value": "1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1"}, {"field": "name", "operator": "equal", "value": "bank_churn"}]}',
|
|
405
480
|
'limit': 50,
|
|
406
481
|
'offset': 0,
|
|
407
482
|
}
|
|
@@ -410,7 +485,7 @@ def test_model_list_success() -> None:
|
|
|
410
485
|
json=LIST_API_RESPONSE,
|
|
411
486
|
match=[matchers.query_param_matcher(params)],
|
|
412
487
|
)
|
|
413
|
-
models = Model.list(project_id=PROJECT_ID)
|
|
488
|
+
models = Model.list(project_id=PROJECT_ID, name=MODEL_NAME)
|
|
414
489
|
for model in models:
|
|
415
490
|
assert isinstance(model, ModelCompact)
|
|
416
491
|
|
|
@@ -471,6 +546,18 @@ def test_update_model_success(mocker) -> None:
|
|
|
471
546
|
model.update()
|
|
472
547
|
assert model.description == 'Test model update'
|
|
473
548
|
|
|
549
|
+
# update version
|
|
550
|
+
new_version = 'v2'
|
|
551
|
+
mocker.patch.dict(API_RESPONSE_200['data'], {'version': new_version})
|
|
552
|
+
|
|
553
|
+
responses.patch(
|
|
554
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
555
|
+
json=API_RESPONSE_200,
|
|
556
|
+
)
|
|
557
|
+
model.version = new_version
|
|
558
|
+
model.update()
|
|
559
|
+
assert model.version == new_version
|
|
560
|
+
|
|
474
561
|
|
|
475
562
|
@responses.activate
|
|
476
563
|
def test_update_model_not_found() -> None:
|
|
@@ -556,3 +643,25 @@ def test_model_schema_dunder_methods() -> None:
|
|
|
556
643
|
# Delete method - KeyError
|
|
557
644
|
with pytest.raises(KeyError):
|
|
558
645
|
del schema['foo']
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
@responses.activate
|
|
649
|
+
def test_model_duplicate() -> None:
|
|
650
|
+
responses.get(
|
|
651
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
652
|
+
json=API_RESPONSE_200,
|
|
653
|
+
)
|
|
654
|
+
model = Model.get(id_=MODEL_ID)
|
|
655
|
+
|
|
656
|
+
assert model.id == UUID(MODEL_ID)
|
|
657
|
+
|
|
658
|
+
# Without version parameter
|
|
659
|
+
model_copy = model.duplicate()
|
|
660
|
+
assert model_copy.id is None
|
|
661
|
+
assert model_copy.version == model.version
|
|
662
|
+
|
|
663
|
+
# With version parameter
|
|
664
|
+
new_version = 'v2'
|
|
665
|
+
model_copy = model.duplicate(version=new_version)
|
|
666
|
+
assert model_copy.id is None
|
|
667
|
+
assert model_copy.version == new_version
|
|
@@ -16,6 +16,7 @@ from fiddler.tests.constants import (
|
|
|
16
16
|
JOB_ID,
|
|
17
17
|
MODEL_ID,
|
|
18
18
|
MODEL_NAME,
|
|
19
|
+
MODEL_VERSION,
|
|
19
20
|
ORG_ID,
|
|
20
21
|
ORG_NAME,
|
|
21
22
|
OUTPUT_DIR,
|
|
@@ -70,6 +71,7 @@ MODEL_API_RESPONSE_200 = {
|
|
|
70
71
|
'data': {
|
|
71
72
|
'id': MODEL_ID,
|
|
72
73
|
'name': MODEL_NAME,
|
|
74
|
+
'version': MODEL_VERSION,
|
|
73
75
|
'project': {
|
|
74
76
|
'id': PROJECT_ID,
|
|
75
77
|
'name': PROJECT_NAME,
|
|
@@ -10,6 +10,7 @@ PROJECT_NAME = 'bank_churn'
|
|
|
10
10
|
PROJECT_ID = '1531bfd9-2ca2-4a7b-bb5a-136c8da09ca1'
|
|
11
11
|
MODEL_NAME = 'bank_churn'
|
|
12
12
|
MODEL_ID = '4531bfd9-2ca2-4a7b-bb5a-136c8da09ca2'
|
|
13
|
+
MODEL_VERSION = 'v1'
|
|
13
14
|
USER_ID = '5531bfd9-2ca2-4a7b-bb5a-136c8da09ca3'
|
|
14
15
|
USER_NAME = 'foo'
|
|
15
16
|
USER_EMAIL = 'foo@fiddler.ai'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.0.0.dev14
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from fiddler.schemas.custom_features import CustomFeature
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ModelSpec(BaseModel):
|
|
9
|
-
"""Model spec defines how model columns are used along with model task"""
|
|
10
|
-
|
|
11
|
-
schema_version: int = 1
|
|
12
|
-
"""Schema version"""
|
|
13
|
-
|
|
14
|
-
inputs: List[str] = []
|
|
15
|
-
"""Feature columns"""
|
|
16
|
-
|
|
17
|
-
outputs: List[str] = []
|
|
18
|
-
"""Prediction columns"""
|
|
19
|
-
|
|
20
|
-
targets: List[str] = []
|
|
21
|
-
"""Label columns"""
|
|
22
|
-
|
|
23
|
-
decisions: List[str] = []
|
|
24
|
-
"""Decisions columns"""
|
|
25
|
-
|
|
26
|
-
metadata: List[str] = []
|
|
27
|
-
"""Metadata columns"""
|
|
28
|
-
|
|
29
|
-
custom_features: List[CustomFeature] = []
|
|
30
|
-
"""Custom feature definitions"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/constants/model_deployment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/custom_expression.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/entities/model_deployment.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/keras_ig_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/packtools/template_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/custom_expression.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/model_deployment.py
RENAMED
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/schemas/model_task_params.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_alert_record.py
RENAMED
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_alert_rule.py
RENAMED
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_baseline.py
RENAMED
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_custom_metric.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model_artifact.py
RENAMED
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model_deployment.py
RENAMED
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler/tests/apis/test_model_surrogate.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/requires.txt
RENAMED
|
File without changes
|
{fiddler-client-3.0.0.dev14 → fiddler-client-3.1.0.dev2}/fiddler_client.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|