fiddler-client 3.0.0.dev10__py3-none-any.whl → 3.1.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.
fiddler/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.0.dev10
1
+ 3.1.0.dev1
fiddler/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from fiddler.connection import Connection, ConnectionMixin, init # noqa
2
4
  from fiddler.constants.alert_rule import ( # noqa
3
5
  AlertCondition,
@@ -5,7 +7,7 @@ from fiddler.constants.alert_rule import ( # noqa
5
7
  CompareTo,
6
8
  Priority,
7
9
  )
8
- from fiddler.constants.baseline import BaselineType, WindowSize # noqa
10
+ from fiddler.constants.baseline import BaselineType, WindowBinSize # noqa
9
11
  from fiddler.constants.dataset import EnvType # noqa
10
12
  from fiddler.constants.job import JobStatus # noqa
11
13
  from fiddler.constants.model import ( # noqa
@@ -19,14 +21,14 @@ from fiddler.constants.model_deployment import ArtifactType, DeploymentType # n
19
21
  from fiddler.constants.xai import ExplainMethod # noqa
20
22
  from fiddler.entities.alert_record import AlertRecord # noqa
21
23
  from fiddler.entities.alert_rule import AlertRule # noqa
22
- from fiddler.entities.baseline import Baseline # noqa
24
+ from fiddler.entities.baseline import Baseline, BaselineCompact # noqa
23
25
  from fiddler.entities.custom_expression import CustomMetric, Segment # noqa
24
- from fiddler.entities.dataset import Dataset # noqa
26
+ from fiddler.entities.dataset import Dataset, DatasetCompact # noqa
25
27
  from fiddler.entities.file import File # noqa
26
28
  from fiddler.entities.job import Job # noqa
27
- from fiddler.entities.model import Model # noqa
29
+ from fiddler.entities.model import Model, ModelCompact # noqa
28
30
  from fiddler.entities.model_deployment import ModelDeployment # noqa
29
- from fiddler.entities.project import Project # noqa
31
+ from fiddler.entities.project import Project, ProjectCompact # noqa
30
32
  from fiddler.entities.webhook import Webhook # noqa
31
33
  from fiddler.exceptions import ( # noqa
32
34
  ApiError,
@@ -62,11 +64,22 @@ from fiddler.schemas.xai_params import XaiParams # noqa
62
64
  from fiddler.utils.logger import set_logging # noqa
63
65
  from fiddler.version import __version__ # noqa
64
66
 
67
+ # Global connection object
68
+ conn: Connection | None = None
69
+
70
+
71
+ def set_conn(conn_: Connection) -> None:
72
+ """Set global conn variable"""
73
+ global conn
74
+ conn = conn_
75
+
76
+
65
77
  __all__ = [
66
78
  '__version__',
67
79
  'Connection',
68
80
  'ConnectionMixin',
69
81
  'init',
82
+ 'conn',
70
83
  # Constants
71
84
  'AlertCondition',
72
85
  'ArtifactStatus',
@@ -82,7 +95,7 @@ __all__ = [
82
95
  'ModelInputType',
83
96
  'ModelTask',
84
97
  'Priority',
85
- 'WindowSize',
98
+ 'WindowBinSize',
86
99
  # Schemas
87
100
  'CustomFeature',
88
101
  'DatasetDataSource',
@@ -103,13 +116,17 @@ __all__ = [
103
116
  'AlertRecord',
104
117
  'AlertRule',
105
118
  'Baseline',
119
+ 'BaselineCompact',
106
120
  'Dataset',
121
+ 'DatasetCompact',
107
122
  'CustomMetric',
108
123
  'File',
109
124
  'Job',
110
125
  'Model',
126
+ 'ModelCompact',
111
127
  'ModelDeployment',
112
128
  'Project',
129
+ 'ProjectCompact',
113
130
  'Segment',
114
131
  'Webhook',
115
132
  # Exceptions
fiddler/connection.py CHANGED
@@ -15,9 +15,6 @@ from fiddler.version import __version__
15
15
 
16
16
  logger = get_logger(__name__)
17
17
 
18
- # Global connection object
19
- connection: Connection | None = None
20
-
21
18
 
22
19
  class Connection:
23
20
  def __init__( # pylint: disable=too-many-arguments
@@ -123,35 +120,37 @@ class Connection:
123
120
 
124
121
  class ConnectionMixin:
125
122
  @classmethod
126
- def _connection(cls) -> Connection:
123
+ def _conn(cls) -> Connection:
127
124
  """Fiddler connection instance"""
128
- assert connection is not None
129
- return connection
125
+ from fiddler import conn
126
+
127
+ assert conn is not None
128
+ return conn
130
129
 
131
130
  @classmethod
132
131
  def _client(cls) -> RequestClient:
133
132
  """Request client instance"""
134
- return cls._connection().client
133
+ return cls._conn().client
135
134
 
136
135
  @property
137
136
  def organization_name(self) -> str:
138
137
  """Organization name property"""
139
- return self._connection().server_info.organization.name
138
+ return self._conn().server_info.organization.name
140
139
 
141
140
  @property
142
141
  def organization_id(self) -> UUID:
143
142
  """Organization id property"""
144
- return self._connection().server_info.organization.id
143
+ return self._conn().server_info.organization.id
145
144
 
146
145
  @classmethod
147
146
  def get_organization_name(cls) -> str:
148
147
  """Organization name"""
149
- return cls._connection().server_info.organization.name
148
+ return cls._conn().server_info.organization.name
150
149
 
151
150
  @classmethod
152
151
  def get_organization_id(cls) -> UUID:
153
152
  """Organization id"""
154
- return cls._connection().server_info.organization.id
153
+ return cls._conn().server_info.organization.id
155
154
 
156
155
 
157
156
  def init( # pylint: disable=too-many-arguments
@@ -173,8 +172,9 @@ def init( # pylint: disable=too-many-arguments
173
172
  :param validate: Whether to validate the server/client version compatibility.
174
173
  Some functionalities might not work if this is turned off.
175
174
  """
176
- global connection # pylint: disable=global-statement
177
- connection = Connection(
175
+ from fiddler import set_conn
176
+
177
+ conn = Connection(
178
178
  url=url,
179
179
  token=token,
180
180
  proxies=proxies,
@@ -182,3 +182,5 @@ def init( # pylint: disable=too-many-arguments
182
182
  verify=verify,
183
183
  validate=validate,
184
184
  )
185
+
186
+ set_conn(conn_=conn)
@@ -8,11 +8,8 @@ class BaselineType(str, enum.Enum):
8
8
 
9
9
 
10
10
  @enum.unique
11
- class WindowSize(enum.IntEnum):
12
- ONE_HOUR = 3600
13
- ONE_DAY = 86400
14
- ONE_WEEK = 604800
15
- ONE_MONTH = 2592000
16
-
17
- def __str__(self) -> str:
18
- return self.name
11
+ class WindowBinSize(str, enum.Enum):
12
+ HOUR = 'Hour'
13
+ DAY = 'Day'
14
+ WEEK = 'Week'
15
+ MONTH = 'Month'
@@ -5,6 +5,7 @@ from datetime import datetime
5
5
  from typing import Any, Iterator
6
6
  from uuid import UUID
7
7
 
8
+ from fiddler.constants.baseline import WindowBinSize
8
9
  from fiddler.constants.dataset import EnvType
9
10
  from fiddler.decorators import handle_api_error
10
11
  from fiddler.entities.base import BaseEntity
@@ -28,8 +29,8 @@ class Baseline(
28
29
  dataset_id: UUID | str | None = None,
29
30
  start_time: int | None = None,
30
31
  end_time: int | None = None,
31
- offset: int | None = None,
32
- window_size: int | None = None,
32
+ offset_delta: int | None = None,
33
+ window_bin_size: WindowBinSize | str | None = None,
33
34
  ) -> None:
34
35
  """Construct a baseline instance."""
35
36
  self.name = name
@@ -39,8 +40,8 @@ class Baseline(
39
40
  self.dataset_id = dataset_id
40
41
  self.start_time = start_time
41
42
  self.end_time = end_time
42
- self.offset = offset
43
- self.window_size = window_size
43
+ self.offset_delta = offset_delta
44
+ self.window_bin_size = window_bin_size
44
45
 
45
46
  self.id: UUID | None = None
46
47
  self.row_count: int | None = None
@@ -73,8 +74,8 @@ class Baseline(
73
74
  type_=resp_obj.type,
74
75
  start_time=resp_obj.start_time,
75
76
  end_time=resp_obj.end_time,
76
- offset=resp_obj.offset,
77
- window_size=resp_obj.window_size,
77
+ offset_delta=resp_obj.offset_delta,
78
+ window_bin_size=resp_obj.window_bin_size,
78
79
  )
79
80
 
80
81
  # Add remaining fields
@@ -109,8 +110,8 @@ class Baseline(
109
110
  'type',
110
111
  'start_time',
111
112
  'end_time',
112
- 'offset',
113
- 'window_size',
113
+ 'offset_delta',
114
+ 'window_bin_size',
114
115
  'created_at',
115
116
  'updated_at',
116
117
  'row_count',
@@ -210,10 +211,10 @@ class Baseline(
210
211
  payload['start_time'] = self.start_time
211
212
  if self.end_time:
212
213
  payload['end_time'] = self.end_time
213
- if self.offset:
214
- payload['offset'] = self.offset
215
- if self.window_size:
216
- payload['window_size'] = self.window_size
214
+ if self.offset_delta:
215
+ payload['offset_delta'] = self.offset_delta
216
+ if self.window_bin_size:
217
+ payload['window_bin_size'] = self.window_bin_size
217
218
 
218
219
  response = self._client().post(
219
220
  url=self._get_url(),
@@ -1,11 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import tempfile
3
4
  from pathlib import Path
4
- from typing import Any, Iterator
5
+ from typing import Any
5
6
  from uuid import UUID
6
7
 
7
8
  import pandas as pd
8
9
  from requests import Response
10
+ from tqdm import tqdm
9
11
 
10
12
  from fiddler.configs import STREAM_EVENT_LIMIT
11
13
  from fiddler.connection import ConnectionMixin
@@ -28,21 +30,6 @@ class EventPublisher(ConnectionMixin):
28
30
  """
29
31
  self.model_id = model_id
30
32
 
31
- def _get_stream_chunks(
32
- self, source: pd.DataFrame | list[dict[str, Any]]
33
- ) -> Iterator[list[dict[str, Any]]]:
34
- """Chunk the source based on stream limit"""
35
-
36
- for i in range(0, len(source), self.STREAM_LIMIT):
37
- chunk = source[i : i + self.STREAM_LIMIT]
38
-
39
- if isinstance(chunk, pd.DataFrame):
40
- events = chunk.to_dict('records')
41
- else:
42
- events = chunk
43
-
44
- yield events
45
-
46
33
  @handle_api_error
47
34
  def publish(
48
35
  self,
@@ -56,13 +43,13 @@ class EventPublisher(ConnectionMixin):
56
43
 
57
44
  :param source: one of:
58
45
  Path or str path: path for data file.
59
- list[dict]: list of event dicts (max 1000) EnvType.PRE_PRODUCTION is not supported
60
- dataframe: events dataframe. EnvType.PRE_PRODUCTION not supported.
46
+ dataframe: events dataframe.
47
+ list[dict]: list of event dicts EnvType.PRE_PRODUCTION is not supported
61
48
  :param environment: Either EnvType.PRE_PRODUCTION or EnvType.PRODUCTION
62
49
  :param dataset_name: Name of the dataset. Not supported for EnvType.PRODUCTION
63
50
  :param update: flag indicating if the events are updates to previously published rows
64
51
 
65
- :return: list[UUID] for list of dicts or dataframe source and Job object for file path source.
52
+ :return: list[UUID] for list of dicts source and Job object for file path or dataframe source.
66
53
  """
67
54
  if isinstance(source, (str, Path)):
68
55
  return self._publish_file(
@@ -72,20 +59,30 @@ class EventPublisher(ConnectionMixin):
72
59
  update=update,
73
60
  )
74
61
 
75
- if isinstance(source, (list, pd.DataFrame)):
62
+ if isinstance(source, pd.DataFrame):
63
+ with tempfile.NamedTemporaryFile(suffix='.csv') as temp_file:
64
+ source.to_csv(temp_file.name, index=False)
65
+ return self._publish_file(
66
+ source=temp_file.name,
67
+ environment=environment,
68
+ dataset_name=dataset_name,
69
+ update=update,
70
+ )
71
+
72
+ elif isinstance(source, list):
76
73
  return self._publish_stream(source=source, update=update)
77
74
 
78
75
  raise ValueError(f'Unsupported source - {type(source)}')
79
76
 
80
77
  def _publish_stream(
81
78
  self,
82
- source: list[dict[str, Any]] | pd.DataFrame,
79
+ source: list[dict[str, Any]],
83
80
  update: bool = False,
84
81
  ) -> list[UUID]:
85
82
  event_ids = []
86
- for events in self._get_stream_chunks(source=source):
83
+ for i in tqdm(range(0, len(source), self.STREAM_LIMIT)):
87
84
  response = self._publish_call(
88
- source=EventsSource(events=events),
85
+ source=EventsSource(events=source[i : i + self.STREAM_LIMIT]),
89
86
  environment=EnvType.PRODUCTION,
90
87
  dataset_name=None,
91
88
  update=update,
fiddler/entities/model.py CHANGED
@@ -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(cls, name: str, project_id: UUID | str) -> Model:
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(), params={'filter': _filter.json()}
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,
@@ -110,7 +110,7 @@ class ModelDeployment(
110
110
  self._refresh_from_response(response=response)
111
111
 
112
112
  @classmethod
113
- def of(cls, model_id: UUID) -> ModelDeployment:
113
+ def of(cls, model_id: UUID | str) -> ModelDeployment:
114
114
  """
115
115
  Get model deployment instance of the given model
116
116
 
@@ -24,8 +24,8 @@ class BaselineResp(BaseModel):
24
24
  type: str
25
25
  start_time: Optional[int]
26
26
  end_time: Optional[int]
27
- offset: Optional[int]
28
- window_size: Optional[int]
27
+ offset_delta: Optional[int]
28
+ window_bin_size: Optional[str]
29
29
  row_count: Optional[int]
30
30
 
31
31
  model: ModelCompactResp
fiddler/schemas/model.py CHANGED
@@ -22,6 +22,7 @@ class ModelCompactResp(BaseModel):
22
22
  class ModelResp(BaseModel):
23
23
  id: UUID
24
24
  name: str
25
+ version: str
25
26
  input_type: str
26
27
  task: str
27
28
  task_params: ModelTaskParams
@@ -29,8 +29,8 @@ API_RESPONSE_200 = {
29
29
  'type': 'STATIC',
30
30
  'start_time': None,
31
31
  'end_time': None,
32
- 'offset': None,
33
- 'window_size': None,
32
+ 'offset_delta': None,
33
+ 'window_bin_size': None,
34
34
  'row_count': 20000,
35
35
  'model': {
36
36
  'id': MODEL_ID,
@@ -80,8 +80,8 @@ LIST_API_RESPONSE = {
80
80
  'type': 'STATIC',
81
81
  'start_time': None,
82
82
  'end_time': None,
83
- 'offset': None,
84
- 'window_size': None,
83
+ 'offset_delta': None,
84
+ 'window_bin_size': None,
85
85
  'row_count': 20000,
86
86
  'model': {
87
87
  'id': MODEL_ID,
@@ -100,52 +100,74 @@ def test_publish_file() -> None:
100
100
 
101
101
 
102
102
  @responses.activate
103
- def test_publish_stream() -> None:
103
+ def test_publish_df() -> None:
104
104
  responses.get(
105
105
  url=f'{URL}/v3/models/{MODEL_ID}',
106
106
  json=MODEL_API_RESPONSE_200,
107
107
  )
108
108
  model = Model.get(id_=MODEL_ID)
109
109
 
110
+ responses.post(
111
+ url=f'{URL}/v3/files/upload',
112
+ json=SINGLE_UPLOAD_200_RESPONSE,
113
+ )
114
+ responses.get(
115
+ url=f'{URL}/v3/jobs/{JOB_ID}',
116
+ json=PUBLISH_JOB_RESPONSE,
117
+ )
118
+
110
119
  responses.post(
111
120
  url=f'{URL}/v3/events',
112
- json=STREAM_PUBLISH_202_API_RESPONSE,
121
+ json=FILE_PUBLISH_202_API_RESPONSE,
113
122
  )
114
123
  publish_response = model.publish(
115
- source=df,
116
- environment=EnvType.PRODUCTION,
124
+ source=df, environment=EnvType.PRE_PRODUCTION, dataset_name='dataset_1'
117
125
  )
118
126
 
119
- assert isinstance(publish_response, list)
120
- assert len(publish_response) == df.shape[0]
127
+ assert isinstance(publish_response, Job)
128
+
129
+ FILE_PUBLISH_202_API_RESPONSE['data']['job']['name'] = 'Publish events'
121
130
 
122
131
  publish_response = model.publish(
123
- source=df.to_dict('records'),
132
+ source=df,
124
133
  environment=EnvType.PRODUCTION,
125
134
  )
126
135
 
127
- assert isinstance(publish_response, list)
128
- assert len(publish_response) == df.shape[0]
136
+ assert isinstance(publish_response, Job)
137
+
138
+ FILE_PUBLISH_202_API_RESPONSE['data']['job']['name'] = 'Publish events'
129
139
 
130
140
 
131
141
  @responses.activate
132
- def test_publish_update() -> None:
142
+ def test_publish_stream() -> None:
133
143
  responses.get(
134
144
  url=f'{URL}/v3/models/{MODEL_ID}',
135
145
  json=MODEL_API_RESPONSE_200,
136
146
  )
137
147
  model = Model.get(id_=MODEL_ID)
138
148
 
139
- responses.patch(
149
+ responses.post(
140
150
  url=f'{URL}/v3/events',
141
151
  json=STREAM_PUBLISH_202_API_RESPONSE,
142
152
  )
153
+
143
154
  publish_response = model.publish(
144
- source=df, environment=EnvType.PRODUCTION, update=True
155
+ source=df.to_dict('records'),
156
+ environment=EnvType.PRODUCTION,
145
157
  )
158
+
146
159
  assert isinstance(publish_response, list)
147
160
  assert len(publish_response) == df.shape[0]
148
161
 
162
+
163
+ @responses.activate
164
+ def test_publish_update() -> None:
165
+ responses.get(
166
+ url=f'{URL}/v3/models/{MODEL_ID}',
167
+ json=MODEL_API_RESPONSE_200,
168
+ )
169
+ model = Model.get(id_=MODEL_ID)
170
+
149
171
  responses.post(
150
172
  url=f'{URL}/v3/files/upload',
151
173
  json=SINGLE_UPLOAD_200_RESPONSE,
@@ -167,3 +189,8 @@ def test_publish_update() -> None:
167
189
  )
168
190
 
169
191
  assert isinstance(publish_response, Job)
192
+
193
+ publish_response = model.publish(
194
+ source=df, environment=EnvType.PRODUCTION, update=True
195
+ )
196
+ assert isinstance(publish_response, Job)
@@ -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, name='model1', project_id=PROJECT_ID
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
@@ -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 = {'project_id': str(PROJECT_ID), 'limit': 50, 'offset': 0}
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 test_model_list_success() -> None:
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,
fiddler/tests/conftest.py CHANGED
@@ -26,5 +26,5 @@ def connection(session_mocker: MockerFixture) -> Connection:
26
26
  }
27
27
  )
28
28
  session_mocker.patch.object(conn, '_get_server_info', return_value=server_info)
29
- session_mocker.patch('fiddler.connection.connection', conn)
29
+ session_mocker.patch('fiddler.conn', conn)
30
30
  yield conn
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fiddler-client
3
- Version: 3.0.0.dev10
3
+ Version: 3.1.0.dev1
4
4
  Summary: Python client for Fiddler Platform
5
5
  Home-page: https://fiddler.ai
6
6
  Author: Fiddler Labs
@@ -1,13 +1,13 @@
1
- fiddler/VERSION,sha256=FtILXJkKcheZdIDv4lVkEqSLQXj3TFXSabECWqPOllU,12
2
- fiddler/__init__.py,sha256=b-mdEuXePogtxmehLezysrqfEyceEk9p-H2GRjLfRZ4,3382
1
+ fiddler/VERSION,sha256=OSg_m1-GiMUFyiK5ruWqv__EjzZJf10D747c9UNhJwA,11
2
+ fiddler/__init__.py,sha256=U9g19CmjOoli4bMAcD_LD-qTmFFBG3uCCIFm34vcTac,3757
3
3
  fiddler/configs.py,sha256=ZimSo0Gk7j1BFkjDHdRdycrGZ8oh-7G5TBXYiOh1HvU,217
4
- fiddler/connection.py,sha256=pYaOyyJytsljofaMyRPV-Vs_i4wHKO48BxIJMqEBxHg,5760
4
+ fiddler/connection.py,sha256=fLdSXpu5dwoK-h4Vtc9nbdKENOJ7jfEmrnDhVAtChck,5677
5
5
  fiddler/decorators.py,sha256=tWZliQQeUGwY0rU52FO9JXuOBueQXVEJywEbrgUEw1U,1820
6
6
  fiddler/exceptions.py,sha256=T4ZpkTYPbnWvUX7y5XehnCyHqQPj3qqsIDKCZQNtaIE,2221
7
7
  fiddler/version.py,sha256=8fyg3UhFpqghMpxbtYIwNcB1lhCG6yTkPBbDS7IrwxY,140
8
8
  fiddler/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  fiddler/constants/alert_rule.py,sha256=cmFq-VKAlQbRKEkTtMmVNdD5R52uMI2zJai6TESFwfs,512
10
- fiddler/constants/baseline.py,sha256=IQbnr3gm4nLroOvcW-gj_2iJz27kkrzHncdsritflq0,298
10
+ fiddler/constants/baseline.py,sha256=uUk63ORFE1Q1-nRlWFUJeF-Zeg0udvfmXs3DWFk3fwc,233
11
11
  fiddler/constants/common.py,sha256=GCW9rzqPkOIcC80j98sKPqxBr8vPLbJ2TrelKaV30yw,400
12
12
  fiddler/constants/dataset.py,sha256=ZxPmzycSlrKpUYShpfTDqfmz8LAebzyBtIV_dBy-pRI,126
13
13
  fiddler/constants/events.py,sha256=3SgjNo4IS-_Nod8wbj98di4B4GctF9R414MZxfQ4MkU,114
@@ -19,15 +19,15 @@ fiddler/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
19
19
  fiddler/entities/alert_record.py,sha256=RcDACWDNpntkiId-JpkLQvVeIbuaZAzn6AWl2zYIh9A,3564
20
20
  fiddler/entities/alert_rule.py,sha256=kLrK1U96gzN8I5G-hTTMmrIA0TywHVt-kb7CipgqjqE,11569
21
21
  fiddler/entities/base.py,sha256=YCTLt1ta8UbD7u-5BW7v_ocA4S7LevEncI5XPS_SB60,2106
22
- fiddler/entities/baseline.py,sha256=IehWDWmIeB73Grb8s0AxP9OotbowTkH9XGPl-ml3W1E,7748
22
+ fiddler/entities/baseline.py,sha256=k3D-K8WC5MkHDILyejRaH1v9jdCIymT96McDBOVQ9A0,7907
23
23
  fiddler/entities/custom_expression.py,sha256=SdS61JiI0gOxWwHAGxkHh1vqS5XsRtyeNSDs5E-Sg2U,6568
24
24
  fiddler/entities/dataset.py,sha256=kwD1pZMG6DQGIjejU7A2KUUBRgOi0o1qbbUX-PSlnGg,4399
25
- fiddler/entities/events.py,sha256=usFxs8Cq0ds1MIrOjZT5jVt3XDXMdGYakOoNFnTFQ8Y,4370
25
+ fiddler/entities/events.py,sha256=SGA4GFmEzS9U7osodTNslfyoXhJe0j_GgyGmgkCXluk,4291
26
26
  fiddler/entities/file.py,sha256=dk8ISfjy0--F2eF23Ae8vGiEZmJW6e9LMqNmKfrY2mE,4710
27
27
  fiddler/entities/job.py,sha256=Feiqo6ns4bRcp2uaV-kuGYAKs90-aYXvzqqi1yLivYE,5220
28
- fiddler/entities/model.py,sha256=J1DoDMZptaOac64LJ_pRmuD2wJ1Wk88SAKA6bSg0W8g,16882
28
+ fiddler/entities/model.py,sha256=J9jb-5BH_DWSyyOoFW9yT45K4BBAvTRcY8G5vgoQiT8,18503
29
29
  fiddler/entities/model_artifact.py,sha256=Y7o1mFs-nVDz7HI9mVBu9ICwkqGD_QbT3q6vf8KKesk,5520
30
- fiddler/entities/model_deployment.py,sha256=vHffixgDu3xjWgA7IKbCpXpYxxspzyuJz7ejhub2yWI,3763
30
+ fiddler/entities/model_deployment.py,sha256=mxEsMYiUO-m9X1ND7UuJ1b3LgEcyvOM5PMEmRvOuftk,3769
31
31
  fiddler/entities/organization.py,sha256=XvUAdBUOYXzdmblxIs4hi0mAg45NtAwy5DBaMiqi47o,1074
32
32
  fiddler/entities/project.py,sha256=G5omjjKHEjvhenMvW-R0bYwrkRVHixIOhTPZb1pS7FI,4631
33
33
  fiddler/entities/surrogate.py,sha256=94RkJmv8uwNhRL8PaliuiRv-R0EXDMKJTimE9boXKwQ,3077
@@ -47,7 +47,7 @@ fiddler/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  fiddler/schemas/alert_record.py,sha256=Edfe264zUwqF856tMblN85CsEa_wn9oZCoLruvsNAbo,668
48
48
  fiddler/schemas/alert_rule.py,sha256=-V0AibEImrfcEZfJ4J_Ed5SuZISOGsk-nIoVlX5mOOg,1222
49
49
  fiddler/schemas/base.py,sha256=upzAmneEz169h_w-UDH_tY0Abo7DeK68YOZ5qVwIMa8,189
50
- fiddler/schemas/baseline.py,sha256=0z7ohzDmUKENmlVZDFx4vB-0SRVTOKaeM1N-pDSCIDk,923
50
+ fiddler/schemas/baseline.py,sha256=tBQji1GLYt0ZYgEK6ZTmXxk5nUYTI6oxMmSjNXnRfWw,933
51
51
  fiddler/schemas/custom_expression.py,sha256=6Y4Q89HIOjUwVS9u9-wMAXvcPMmtQ7puLEkx27Gr-wY,844
52
52
  fiddler/schemas/custom_features.py,sha256=G0UqikCyvhnLg6oUAutvq4mEsGgVcLkPlJaMCbRZj68,5382
53
53
  fiddler/schemas/dataset.py,sha256=rGmpMrMfPLSs9d3_sxDTjrKqWp-o-bCe9pf_nlYyHfw,657
@@ -55,7 +55,7 @@ fiddler/schemas/events.py,sha256=dH6SGPBO_rgGZetIhSo4Fq0L1pTU7TEKR7zW7gg3fnI,409
55
55
  fiddler/schemas/file.py,sha256=z_7bOxKbwQsgI8F7MMQvC6RE5dgdzYCMyD5XcBirjCc,462
56
56
  fiddler/schemas/filter_query.py,sha256=XP8SoFGSJOo9yf3fA9dPqpKdCJuaUpbKbYixn46lBF0,1325
57
57
  fiddler/schemas/job.py,sha256=6q3SiHp43ah0R0eIO77DNgJRug-dejI13NZAd_7c0sk,354
58
- fiddler/schemas/model.py,sha256=1z7W0Ct180z3cku2AhwGFI9ry2MgVKgEy7GvVPJ0rJM,1361
58
+ fiddler/schemas/model.py,sha256=mGMTszQL-VpcRl9yXsYdN5UnTXuCA0B8rvmyxktNUZs,1378
59
59
  fiddler/schemas/model_deployment.py,sha256=s1moOBT7JIMWgGZ4ALxgZJhB4ulVK6i2VkNp7_mOJKo,1128
60
60
  fiddler/schemas/model_schema.py,sha256=nagwbYFoWG6CzBTYYYuQNMpGfA6i9da_WPa8uO2IBCo,1914
61
61
  fiddler/schemas/model_spec.py,sha256=RiZd-efabsJVfHCI5kXRs_6RrWj4xZB6vqajHSDqxgc,642
@@ -69,8 +69,8 @@ fiddler/schemas/webhook.py,sha256=Utg1wRylr5L0CYc47k7iLQdlVCL0L6S29jVntNwMzbA,46
69
69
  fiddler/schemas/xai.py,sha256=AZbjjBlTDZbQGj3U-pTM1UX_LJltjy__2t-kM2v5FuY,739
70
70
  fiddler/schemas/xai_params.py,sha256=7WbUCBojzZckjOA2NUxnk5y3M2WKKXclSzkt5HBfyUU,313
71
71
  fiddler/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
- fiddler/tests/conftest.py,sha256=xmKmq9h2VBqwknL9CE1EUF9uRMQRNmjDPCJszabhf2U,857
73
- fiddler/tests/constants.py,sha256=-_uoidMv6eQ-ldHCN5u_uBXuX3aS4YuylaUSbBfGHYY,1081
72
+ fiddler/tests/conftest.py,sha256=Dmz9FKAFHYdq1AWmcY7NES9pU4cbY9qKWQiojjaX_0E,840
73
+ fiddler/tests/constants.py,sha256=X0UNIfj47HsTBaThMdxZqi3boY_qam25SMrrcdXr-4M,1102
74
74
  fiddler/tests/test_connection.py,sha256=d8WoB0QRZEObWfeRAZRXRm1kw9wfEysmeo4Bld7x8js,1865
75
75
  fiddler/tests/test_json_encoder.py,sha256=GJeFT5tTA4RTfZn1q2xm1V5SEj5DNsW3LeHPVfFxcFw,783
76
76
  fiddler/tests/test_logger.py,sha256=StDWgtVoBOplRsvcH44Su-ikOWcafT29Kof-K-jiTxc,312
@@ -79,30 +79,30 @@ fiddler/tests/utils.py,sha256=FEDbASW4pYZktdEK2FLnIDyZCwBzpb60m6EzkvOkwSc,335
79
79
  fiddler/tests/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
80
  fiddler/tests/apis/test_alert_record.py,sha256=_0EBRDn87TqTiO1KYEHKQQVtVZjj4lYjbt8Ix-RRTSg,3118
81
81
  fiddler/tests/apis/test_alert_rule.py,sha256=3fmcxiGXOokMqFRWo5w4CL4m0k6rCnG17ZRfj1wlZ04,11231
82
- fiddler/tests/apis/test_baseline.py,sha256=d-fu-XV5WpaRh8jbNBCk8EpV6N8A-Ls8EstC8qScuBM,7474
82
+ fiddler/tests/apis/test_baseline.py,sha256=R_vvbZdSenpYMSydurENJrE_uNWE3sJR9sHJksfU_Jk,7494
83
83
  fiddler/tests/apis/test_custom_metric.py,sha256=QlNa80M9PxqaqzW-3nCtH5kKLRHYu2iqFDautBusbos,8208
84
84
  fiddler/tests/apis/test_dataset.py,sha256=1Xc9Ng91fLMc2C6dpKfse42fQ0anza3ZOKOD1TqCvTQ,4636
85
- fiddler/tests/apis/test_events.py,sha256=e5sd3dIfMPyHoX-jX1QjCP90D-2ijJq1NERGbbfmSls,4510
85
+ fiddler/tests/apis/test_events.py,sha256=GzdfSqBN0WAGCIjWKmz1WPHsRafBiZnWtmd8feiNplw,5134
86
86
  fiddler/tests/apis/test_files.py,sha256=-BisPck7bHMSW3N40ffdQJe027Qe3079tjTlU2OI9DU,4501
87
- fiddler/tests/apis/test_generate_model.py,sha256=-MtCnW4sntm7W9c12R9eorIUqEnBq5K_FqhSqdhInJE,4970
87
+ fiddler/tests/apis/test_generate_model.py,sha256=J8foDsZIUoHJyzLODQM57jw8OFVD81jc67RIubq-CVs,5089
88
88
  fiddler/tests/apis/test_job.py,sha256=GlJXhxK60q9u5QJ6ToLrw4y1G3M0DzAAR2u-JDbk3D0,1891
89
89
  fiddler/tests/apis/test_mixin.py,sha256=CmiyAch8Mzoi3Jru-8PWVxWlX-y30WMuoymSc9QXFwc,2453
90
- fiddler/tests/apis/test_model.py,sha256=1ufNtCfEzoiVaP1dxCOCBpI8e0dBt81JuZY8kkdGnI4,14692
90
+ fiddler/tests/apis/test_model.py,sha256=AL4BdP8vZjRLkh0XESFKjLzg5gVG-vxhnyE6adku6tA,18346
91
91
  fiddler/tests/apis/test_model_artifact.py,sha256=oQVasstDc41EesAzN39wCTZi7KtpeQdVcGcLxERjmw0,5635
92
92
  fiddler/tests/apis/test_model_deployment.py,sha256=AWGdbepFrU3qT17XAZC68n8LlXh7OKNqSwg3_ug9G5I,2441
93
93
  fiddler/tests/apis/test_model_surrogate.py,sha256=h3OPgD1-_n6gTd0YH_hDcBBRjBfXv1xUsZxNWUU69KQ,4443
94
94
  fiddler/tests/apis/test_project.py,sha256=IEYT3imD4dZJg-OT888G4jQJ_AxxHN5_VkCHcmwUnGA,6015
95
95
  fiddler/tests/apis/test_segment.py,sha256=hQiXpZEKLJrnlRBLLMsP3jph8H8K7AEUw17sMK6BuF8,7804
96
96
  fiddler/tests/apis/test_webhook.py,sha256=DTaEI9r2lossAaXb3b1CX4C8L3bYAzZmLIWH8VeauUs,6440
97
- fiddler/tests/apis/test_xai.py,sha256=5TzRv3jSTn2xi3qpwPyKyybEVjHcSyszSHTLzuXU30s,28537
97
+ fiddler/tests/apis/test_xai.py,sha256=mV-bcu6Tkw_wM4nCc9Uf6OXU38Hz0gX3eiVMCLGAsbQ,28590
98
98
  fiddler/utils/__init__.py,sha256=ooAJR6_tVaF6UKZriz5ynZPj8IeCzaDIPKV23F-e4Fk,53
99
99
  fiddler/utils/helpers.py,sha256=Xl_T_se9SOeMTmVJAOVzzmkekUsmpFMlAb2KvPCWfTw,2908
100
100
  fiddler/utils/logger.py,sha256=FdJ3LkS9dbRjWsw5oJmNNsd7q0XRVEIvx5-TWys7L0k,669
101
101
  fiddler/utils/model_generator.py,sha256=TwQMQDpy-0gcq6HyL68s37N-sk_nGPq33mmppK6i7hI,2203
102
102
  fiddler/utils/validations.py,sha256=i8NtgrpCsitq6BPa5lygpKDh07oaOXu7PAlCIcMvqzY,408
103
103
  fiddler/utils/version.py,sha256=iC8Ry7UFl9EJW_xU1WbzO_l4yK6V7eQ6U5exB3xT864,531
104
- fiddler_client-3.0.0.dev10.dist-info/LICENSE.txt,sha256=w8-LUAb_VLBWSsCNmih0pAqLIicJfGu8OJXpDjkIg_o,559
105
- fiddler_client-3.0.0.dev10.dist-info/METADATA,sha256=f7Rl4ZVdaXrxBePBIz8VzjGzyr8m3SYT_clZ165wQ-g,20680
106
- fiddler_client-3.0.0.dev10.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
107
- fiddler_client-3.0.0.dev10.dist-info/top_level.txt,sha256=ndC6LqvKmrTTs8czRlBOYdYgSqZbHuMf0zHt_HWpzzk,8
108
- fiddler_client-3.0.0.dev10.dist-info/RECORD,,
104
+ fiddler_client-3.1.0.dev1.dist-info/LICENSE.txt,sha256=w8-LUAb_VLBWSsCNmih0pAqLIicJfGu8OJXpDjkIg_o,559
105
+ fiddler_client-3.1.0.dev1.dist-info/METADATA,sha256=V8DvhQQmpuFptAUCsonzdA6mmbEVYzQmtU_qxMR0pUU,20679
106
+ fiddler_client-3.1.0.dev1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
107
+ fiddler_client-3.1.0.dev1.dist-info/top_level.txt,sha256=ndC6LqvKmrTTs8czRlBOYdYgSqZbHuMf0zHt_HWpzzk,8
108
+ fiddler_client-3.1.0.dev1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5