fiddler-client 3.0.0.dev3__py3-none-any.whl → 3.0.0.dev5__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 +1 -1
- fiddler/__init__.py +3 -0
- fiddler/constants/common.py +0 -1
- fiddler/entities/custom_metric.py +222 -0
- fiddler/entities/file.py +5 -8
- fiddler/entities/model_artifact.py +2 -1
- fiddler/libs/http_client.py +10 -32
- fiddler/schemas/custom_metric.py +23 -0
- fiddler/tests/apis/test_custom_metric.py +352 -0
- fiddler/tests/test_utils.py +32 -1
- fiddler/utils/helpers.py +1 -1
- {fiddler_client-3.0.0.dev3.dist-info → fiddler_client-3.0.0.dev5.dist-info}/METADATA +5 -1
- {fiddler_client-3.0.0.dev3.dist-info → fiddler_client-3.0.0.dev5.dist-info}/RECORD +16 -14
- fiddler/_version.py +0 -1
- {fiddler_client-3.0.0.dev3.dist-info → fiddler_client-3.0.0.dev5.dist-info}/LICENSE.txt +0 -0
- {fiddler_client-3.0.0.dev3.dist-info → fiddler_client-3.0.0.dev5.dist-info}/WHEEL +0 -0
- {fiddler_client-3.0.0.dev3.dist-info → fiddler_client-3.0.0.dev5.dist-info}/top_level.txt +0 -0
fiddler/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.0.0.
|
|
1
|
+
3.0.0.dev5
|
fiddler/__init__.py
CHANGED
|
@@ -20,6 +20,7 @@ from fiddler.constants.xai import ExplainMethod # noqa
|
|
|
20
20
|
from fiddler.entities.alert_record import AlertRecord # noqa
|
|
21
21
|
from fiddler.entities.alert_rule import AlertRule # noqa
|
|
22
22
|
from fiddler.entities.baseline import Baseline # noqa
|
|
23
|
+
from fiddler.entities.custom_metric import CustomMetric, Segment # noqa
|
|
23
24
|
from fiddler.entities.dataset import Dataset # noqa
|
|
24
25
|
from fiddler.entities.file import File # noqa
|
|
25
26
|
from fiddler.entities.job import Job # noqa
|
|
@@ -103,11 +104,13 @@ __all__ = [
|
|
|
103
104
|
'AlertRule',
|
|
104
105
|
'Baseline',
|
|
105
106
|
'Dataset',
|
|
107
|
+
'CustomMetric',
|
|
106
108
|
'File',
|
|
107
109
|
'Job',
|
|
108
110
|
'Model',
|
|
109
111
|
'ModelDeployment',
|
|
110
112
|
'Project',
|
|
113
|
+
'Segment',
|
|
111
114
|
'Webhook',
|
|
112
115
|
# Exceptions
|
|
113
116
|
'NotFound',
|
fiddler/constants/common.py
CHANGED
|
@@ -11,5 +11,4 @@ CONTENT_TYPE_OCTET_STREAM = 'application/octet-stream'
|
|
|
11
11
|
CONTENT_TYPE_OCTET_STREAM_HEADER = {CONTENT_TYPE_HEADER_KEY: CONTENT_TYPE_OCTET_STREAM}
|
|
12
12
|
|
|
13
13
|
# Multi-part upload
|
|
14
|
-
MULTI_PART_UPLOAD_SIZE_THRESHOLD = 5 * 1024 * 1024 # 5MB in bytes
|
|
15
14
|
MULTI_PART_CHUNK_SIZE = 100 * 1024 * 1024 # 100MB in bytes
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Iterator
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from fiddler.decorators import handle_api_error
|
|
9
|
+
from fiddler.entities.base import BaseEntity
|
|
10
|
+
from fiddler.entities.model import Model
|
|
11
|
+
from fiddler.schemas.custom_metric import (
|
|
12
|
+
CustomExpressionResp,
|
|
13
|
+
CustomMetricResp,
|
|
14
|
+
SegmentResp,
|
|
15
|
+
)
|
|
16
|
+
from fiddler.schemas.filter_query import OperatorType, QueryCondition, QueryRule
|
|
17
|
+
from fiddler.utils.helpers import raise_not_found
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CustomExpression(BaseEntity):
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
name: str,
|
|
24
|
+
model_id: UUID,
|
|
25
|
+
definition: str,
|
|
26
|
+
description: str | None = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Construct a custom expression instance."""
|
|
29
|
+
self.name = name
|
|
30
|
+
self.model_id = model_id
|
|
31
|
+
self.definition = definition
|
|
32
|
+
self.description = description
|
|
33
|
+
|
|
34
|
+
self.id: UUID | None = None
|
|
35
|
+
self.created_at: datetime | None = None
|
|
36
|
+
|
|
37
|
+
# Deserialized response object
|
|
38
|
+
self._resp: CustomExpressionResp | None = None
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def _get_url(id_: UUID | str | None = None) -> str:
|
|
43
|
+
"""Get custom expression resource/item url."""
|
|
44
|
+
|
|
45
|
+
def _refresh(self, data: dict) -> None:
|
|
46
|
+
"""Refresh the fields of this instance from the given response dictionary"""
|
|
47
|
+
# Deserialize the response
|
|
48
|
+
resp_obj = CustomMetricResp(**data)
|
|
49
|
+
assert self.model_id
|
|
50
|
+
fields = [
|
|
51
|
+
'id',
|
|
52
|
+
'name',
|
|
53
|
+
'definition',
|
|
54
|
+
'description',
|
|
55
|
+
'created_at',
|
|
56
|
+
]
|
|
57
|
+
for field in fields:
|
|
58
|
+
setattr(self, field, getattr(resp_obj, field, None))
|
|
59
|
+
|
|
60
|
+
self._resp = resp_obj
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def _from_dict(cls, data: dict) -> CustomExpression:
|
|
64
|
+
"""Build entity object from the given dictionary."""
|
|
65
|
+
|
|
66
|
+
# Deserialize the response
|
|
67
|
+
resp_obj = CustomMetricResp(**data)
|
|
68
|
+
model = Model.from_name(
|
|
69
|
+
name=resp_obj.model_name, project_name=resp_obj.project_name
|
|
70
|
+
)
|
|
71
|
+
assert model.id
|
|
72
|
+
# Initialize
|
|
73
|
+
instance = cls(
|
|
74
|
+
name=resp_obj.name,
|
|
75
|
+
model_id=model.id,
|
|
76
|
+
definition=resp_obj.definition,
|
|
77
|
+
description=resp_obj.description,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Add remaining fields
|
|
81
|
+
fields = [
|
|
82
|
+
'id',
|
|
83
|
+
'created_at',
|
|
84
|
+
]
|
|
85
|
+
for field in fields:
|
|
86
|
+
setattr(instance, field, getattr(resp_obj, field, None))
|
|
87
|
+
|
|
88
|
+
instance._resp = resp_obj
|
|
89
|
+
|
|
90
|
+
return instance
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
@handle_api_error
|
|
94
|
+
def get(cls, id_: UUID | str) -> CustomExpression:
|
|
95
|
+
"""
|
|
96
|
+
Get the CustomMetric instance using custom metric id.
|
|
97
|
+
|
|
98
|
+
:param id_: unique uuid format identifier for custom metric
|
|
99
|
+
:return: CustomMetric instance
|
|
100
|
+
"""
|
|
101
|
+
response = cls._client().get(url=cls._get_url(id_=id_))
|
|
102
|
+
return cls._from_response(response=response)
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
@handle_api_error
|
|
106
|
+
def from_name(
|
|
107
|
+
cls, name: str, model_name: str, project_name: str
|
|
108
|
+
) -> CustomExpression:
|
|
109
|
+
"""
|
|
110
|
+
Get the custom metric instance using custom metric name, model name and project name.
|
|
111
|
+
|
|
112
|
+
:param name: Custom metric name
|
|
113
|
+
:param model_name: Name of the model associated with the custom metric
|
|
114
|
+
:param project_name: Name of the project associated with the custom metric
|
|
115
|
+
|
|
116
|
+
:return: CustomMetric instance for the provided params
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
_filter = QueryCondition(
|
|
120
|
+
rules=[
|
|
121
|
+
QueryRule(field='name', operator=OperatorType.EQUAL, value=name),
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
params: dict[str, Any] = {
|
|
125
|
+
'filter': _filter.json(),
|
|
126
|
+
'organization_name': cls.get_organization_name(),
|
|
127
|
+
'project_name': project_name,
|
|
128
|
+
'model_name': model_name,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
response = cls._client().get(
|
|
132
|
+
url=cls._get_url(),
|
|
133
|
+
params=params,
|
|
134
|
+
)
|
|
135
|
+
if response.json()['data']['total'] == 0:
|
|
136
|
+
raise_not_found('Custom metric not found for the given identifier')
|
|
137
|
+
|
|
138
|
+
return cls._from_dict(data=response.json()['data']['items'][0])
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
@handle_api_error
|
|
142
|
+
def list(
|
|
143
|
+
cls,
|
|
144
|
+
model_id: UUID,
|
|
145
|
+
) -> Iterator[CustomExpression]:
|
|
146
|
+
"""Get a list of all custom metrics in the organization."""
|
|
147
|
+
|
|
148
|
+
model = Model.get(id_=model_id)
|
|
149
|
+
params: dict[str, Any] = {
|
|
150
|
+
'organization_name': cls.get_organization_name(),
|
|
151
|
+
'project_name': model.project.name,
|
|
152
|
+
'model_name': model.name,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for custom_metric in cls._paginate(
|
|
156
|
+
url=cls._get_url(),
|
|
157
|
+
params=params,
|
|
158
|
+
):
|
|
159
|
+
yield cls._from_dict(data=custom_metric)
|
|
160
|
+
|
|
161
|
+
@handle_api_error
|
|
162
|
+
def create(self) -> CustomExpression:
|
|
163
|
+
"""Create a new custom metric."""
|
|
164
|
+
model = Model.get(id_=self.model_id)
|
|
165
|
+
payload = {
|
|
166
|
+
'name': self.name,
|
|
167
|
+
'organization_name': self.get_organization_name(),
|
|
168
|
+
'project_name': model.project.name,
|
|
169
|
+
'model_name': model.name,
|
|
170
|
+
'definition': self.definition,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if self.description:
|
|
174
|
+
payload['description'] = self.description
|
|
175
|
+
|
|
176
|
+
response = self._client().post(
|
|
177
|
+
url=self._get_url(),
|
|
178
|
+
data=payload,
|
|
179
|
+
)
|
|
180
|
+
self._refresh_from_response(response=response)
|
|
181
|
+
return self
|
|
182
|
+
|
|
183
|
+
@handle_api_error
|
|
184
|
+
def delete(self) -> None:
|
|
185
|
+
"""Delete a custom metric."""
|
|
186
|
+
assert self.id is not None
|
|
187
|
+
|
|
188
|
+
self._client().delete(url=self._get_url(id_=self.id))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class CustomMetric(CustomExpression):
|
|
192
|
+
def __init__(
|
|
193
|
+
self, name: str, model_id: UUID, definition: str, description: str | None = None
|
|
194
|
+
) -> None:
|
|
195
|
+
"""Construct a custom metric instance."""
|
|
196
|
+
super().__init__(name, model_id, definition, description)
|
|
197
|
+
|
|
198
|
+
# Deserialized response object
|
|
199
|
+
self._resp: CustomMetricResp | None = None
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def _get_url(id_: UUID | str | None = None) -> str:
|
|
203
|
+
"""Get custom metric resource/item url."""
|
|
204
|
+
url = '/v2/custom-metrics'
|
|
205
|
+
return url if not id_ else f'{url}/{id_}'
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class Segment(CustomExpression):
|
|
209
|
+
def __init__(
|
|
210
|
+
self, name: str, model_id: UUID, definition: str, description: str | None = None
|
|
211
|
+
) -> None:
|
|
212
|
+
"""Construct a segment instance."""
|
|
213
|
+
super().__init__(name, model_id, definition, description)
|
|
214
|
+
|
|
215
|
+
# Deserialized response object
|
|
216
|
+
self._resp: SegmentResp | None = None
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def _get_url(id_: UUID | str | None = None) -> str:
|
|
220
|
+
"""Get segment resource/item url."""
|
|
221
|
+
url = '/v2/segments'
|
|
222
|
+
return url if not id_ else f'{url}/{id_}'
|
fiddler/entities/file.py
CHANGED
|
@@ -8,7 +8,6 @@ from typing import Any
|
|
|
8
8
|
from uuid import UUID
|
|
9
9
|
|
|
10
10
|
from requests import Response
|
|
11
|
-
from requests_toolbelt import MultipartEncoder
|
|
12
11
|
|
|
13
12
|
from fiddler.constants.common import MULTI_PART_CHUNK_SIZE
|
|
14
13
|
from fiddler.decorators import handle_api_error
|
|
@@ -74,14 +73,12 @@ class File(BaseEntity, CreatedByMixin, UpdatedByMixin):
|
|
|
74
73
|
@handle_api_error
|
|
75
74
|
def single_upload(self) -> File:
|
|
76
75
|
"""Single part file upload"""
|
|
77
|
-
with open(self.path, 'rb') as f:
|
|
78
|
-
multipart_data = MultipartEncoder(fields={'file': (self.name, f)})
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
response = self._client().post(
|
|
78
|
+
url='/v3/files/upload',
|
|
79
|
+
files={'file': (self.name, open(self.path, 'rb'))},
|
|
80
|
+
headers={'Content-Type': None},
|
|
81
|
+
)
|
|
85
82
|
|
|
86
83
|
self._refresh_from_response(response)
|
|
87
84
|
return self
|
|
@@ -66,9 +66,10 @@ class ModelArtifact(ConnectionMixin):
|
|
|
66
66
|
)
|
|
67
67
|
|
|
68
68
|
logger.info(
|
|
69
|
-
'Model[%s] - Model artifact tar file created at %s',
|
|
69
|
+
'Model[%s] - Model artifact tar file created at %s - %d bytes',
|
|
70
70
|
self.model_id,
|
|
71
71
|
file_path,
|
|
72
|
+
os.path.getsize(file_path),
|
|
72
73
|
)
|
|
73
74
|
|
|
74
75
|
# Upload file
|
fiddler/libs/http_client.py
CHANGED
|
@@ -7,7 +7,6 @@ from urllib.parse import urljoin
|
|
|
7
7
|
import requests
|
|
8
8
|
import simplejson
|
|
9
9
|
from requests.adapters import HTTPAdapter
|
|
10
|
-
from requests_toolbelt.multipart.encoder import MultipartEncoder
|
|
11
10
|
|
|
12
11
|
from fiddler.constants.common import JSON_CONTENT_TYPE
|
|
13
12
|
from fiddler.exceptions import ( # pylint: disable=redefined-builtin
|
|
@@ -51,7 +50,6 @@ class RequestClient:
|
|
|
51
50
|
headers: dict | None = None,
|
|
52
51
|
data: dict | bytes | None = None,
|
|
53
52
|
timeout: int | None = None,
|
|
54
|
-
files_encoders: dict[str, MultipartEncoder] | None = None,
|
|
55
53
|
**kwargs: Any,
|
|
56
54
|
) -> requests.Response:
|
|
57
55
|
"""
|
|
@@ -63,9 +61,6 @@ class RequestClient:
|
|
|
63
61
|
:param headers: Request headers
|
|
64
62
|
:param data: Dict/binary data
|
|
65
63
|
:param timeout: Request timeout in seconds
|
|
66
|
-
:param files_encoders: Dictionary of 'filename': file-like-objects
|
|
67
|
-
for multipart encoding upload. Make sure all MultipartEncoder values have
|
|
68
|
-
same content_type.
|
|
69
64
|
"""
|
|
70
65
|
logger.debug('Making %s call to %s', method, url)
|
|
71
66
|
|
|
@@ -87,31 +82,16 @@ class RequestClient:
|
|
|
87
82
|
# So setting that as default here
|
|
88
83
|
kwargs.setdefault('verify', self.session.verify)
|
|
89
84
|
try:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
timeout=timeout,
|
|
101
|
-
proxies=self.proxies,
|
|
102
|
-
**kwargs,
|
|
103
|
-
)
|
|
104
|
-
else:
|
|
105
|
-
response = self.session.request(
|
|
106
|
-
method,
|
|
107
|
-
full_url,
|
|
108
|
-
params=params,
|
|
109
|
-
data=data,
|
|
110
|
-
headers=request_headers,
|
|
111
|
-
timeout=timeout,
|
|
112
|
-
proxies=self.proxies,
|
|
113
|
-
**kwargs,
|
|
114
|
-
)
|
|
85
|
+
response = self.session.request(
|
|
86
|
+
method,
|
|
87
|
+
full_url,
|
|
88
|
+
params=params,
|
|
89
|
+
data=data,
|
|
90
|
+
headers=request_headers,
|
|
91
|
+
timeout=timeout,
|
|
92
|
+
proxies=self.proxies,
|
|
93
|
+
**kwargs,
|
|
94
|
+
)
|
|
115
95
|
|
|
116
96
|
except requests.Timeout as exc:
|
|
117
97
|
logger.error('%s call failed with Timeout error for URL %s', method, url)
|
|
@@ -173,7 +153,6 @@ class RequestClient:
|
|
|
173
153
|
headers: dict | None = None,
|
|
174
154
|
timeout: int | None = None,
|
|
175
155
|
data: dict | bytes | None = None,
|
|
176
|
-
files_encoders: dict[str, MultipartEncoder] | None = None,
|
|
177
156
|
**kwargs: dict[str, Any],
|
|
178
157
|
) -> requests.Response:
|
|
179
158
|
"""Construct a post request instance."""
|
|
@@ -184,7 +163,6 @@ class RequestClient:
|
|
|
184
163
|
headers=headers,
|
|
185
164
|
timeout=timeout,
|
|
186
165
|
data=data,
|
|
187
|
-
files_encoders=files_encoders,
|
|
188
166
|
**kwargs,
|
|
189
167
|
)
|
|
190
168
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from fiddler.schemas.base import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CustomExpressionResp(BaseModel):
|
|
9
|
+
id: UUID
|
|
10
|
+
name: str
|
|
11
|
+
model_name: str
|
|
12
|
+
project_name: str
|
|
13
|
+
definition: str
|
|
14
|
+
description: Optional[str]
|
|
15
|
+
created_at: datetime
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CustomMetricResp(CustomExpressionResp):
|
|
19
|
+
"""Custom metric response object"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SegmentResp(CustomExpressionResp):
|
|
23
|
+
"""Segment response object"""
|
|
@@ -0,0 +1,352 @@
|
|
|
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 fiddler.entities.custom_metric import CustomMetric
|
|
9
|
+
from fiddler.exceptions import Conflict, NotFound
|
|
10
|
+
from fiddler.tests.apis.test_model import API_RESPONSE_200 as MODEL_API_RESPONSE_200
|
|
11
|
+
from fiddler.tests.apis.test_model import (
|
|
12
|
+
API_RESPONSE_FROM_NAME as MODEL_API_RESPONSE_FROM_NAME,
|
|
13
|
+
)
|
|
14
|
+
from fiddler.tests.constants import MODEL_ID, MODEL_NAME, ORG_NAME, PROJECT_NAME, URL
|
|
15
|
+
|
|
16
|
+
CUSTOM_METRIC_ID = '7057867c-6dd8-4915-89f2-a5f253dd4a3a'
|
|
17
|
+
CUSTOM_METRIC_NAME = 'xyzabc'
|
|
18
|
+
|
|
19
|
+
API_RESPONSE_200 = {
|
|
20
|
+
'data': {
|
|
21
|
+
'description': 'meh',
|
|
22
|
+
'definition': "average(\"Age\")",
|
|
23
|
+
'created_by': {
|
|
24
|
+
'id': 2,
|
|
25
|
+
'full_name': 'Nikhil Singh',
|
|
26
|
+
'email': 'nikhil@fiddler.ai',
|
|
27
|
+
},
|
|
28
|
+
'name': CUSTOM_METRIC_NAME,
|
|
29
|
+
'id': CUSTOM_METRIC_ID,
|
|
30
|
+
'organization_name': ORG_NAME,
|
|
31
|
+
'model_name': MODEL_NAME,
|
|
32
|
+
'project_name': PROJECT_NAME,
|
|
33
|
+
'created_at': '2024-02-13T07:56:04.275549+00:00',
|
|
34
|
+
},
|
|
35
|
+
'api_version': '2.0',
|
|
36
|
+
'kind': 'NORMAL',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
API_RESPONSE_404 = {
|
|
40
|
+
'error': {
|
|
41
|
+
'code': 404,
|
|
42
|
+
'message': "CustomMetric({'uuid': UUID('7057867c-6dd8-4915-89f2-a5f253dd4a3a')}) not found",
|
|
43
|
+
'errors': [
|
|
44
|
+
{
|
|
45
|
+
'reason': 'ObjectNotFound',
|
|
46
|
+
'message': "CustomMetric({'uuid': UUID('7057867c-6dd8-4915-89f2-a5f253dd4a3a')}) not found",
|
|
47
|
+
'help': '',
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
'api_version': '2.0',
|
|
52
|
+
'kind': 'ERROR',
|
|
53
|
+
}
|
|
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
|
+
EMPTY_LIST_API_RESPONSE = {
|
|
68
|
+
'data': {
|
|
69
|
+
'page_size': 100,
|
|
70
|
+
'total': 0,
|
|
71
|
+
'item_count': 0,
|
|
72
|
+
'page_count': 1,
|
|
73
|
+
'page_index': 1,
|
|
74
|
+
'offset': 0,
|
|
75
|
+
'items': [],
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
LIST_API_RESPONSE = {
|
|
80
|
+
'data': {
|
|
81
|
+
'page_size': 100,
|
|
82
|
+
'total': 2,
|
|
83
|
+
'item_count': 2,
|
|
84
|
+
'page_count': 1,
|
|
85
|
+
'page_index': 1,
|
|
86
|
+
'offset': 0,
|
|
87
|
+
'items': [
|
|
88
|
+
API_RESPONSE_200['data'],
|
|
89
|
+
{
|
|
90
|
+
'description': 'meh',
|
|
91
|
+
'definition': "average(\"Age\")",
|
|
92
|
+
'created_by': {
|
|
93
|
+
'id': 2,
|
|
94
|
+
'full_name': 'Nikhil Singh',
|
|
95
|
+
'email': 'nikhil@fiddler.ai',
|
|
96
|
+
},
|
|
97
|
+
'name': 'abcxyz',
|
|
98
|
+
'id': 'a509c450-c00b-4b5c-9a96-89c43e287e5a',
|
|
99
|
+
'organization_name': ORG_NAME,
|
|
100
|
+
'model_name': MODEL_NAME,
|
|
101
|
+
'project_name': PROJECT_NAME,
|
|
102
|
+
'created_at': '2024-02-12T07:56:04.275549+00:00',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
API_RESPONSE_409 = {
|
|
109
|
+
'error': {
|
|
110
|
+
'code': 409,
|
|
111
|
+
'message': 'Custom metric with the same name already exists for this model',
|
|
112
|
+
'errors': [
|
|
113
|
+
{
|
|
114
|
+
'reason': 'Conflict',
|
|
115
|
+
'message': 'Custom metric with the same name already exists for this model',
|
|
116
|
+
'help': '',
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
'api_version': '2.0',
|
|
121
|
+
'kind': 'ERROR',
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@responses.activate
|
|
126
|
+
def test_get_custom_metric() -> None:
|
|
127
|
+
responses.get(
|
|
128
|
+
url=f'{URL}/v2/custom-metrics/{CUSTOM_METRIC_ID}',
|
|
129
|
+
json=API_RESPONSE_200,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
responses.get(
|
|
133
|
+
url=f'{URL}/v3/models',
|
|
134
|
+
json=MODEL_API_RESPONSE_FROM_NAME,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
responses.get(
|
|
138
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
139
|
+
json=MODEL_API_RESPONSE_200,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
cm = CustomMetric.get(id_=CUSTOM_METRIC_ID)
|
|
143
|
+
assert isinstance(cm, CustomMetric)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@responses.activate
|
|
147
|
+
def test_get_cm_not_found() -> None:
|
|
148
|
+
responses.get(
|
|
149
|
+
url=f'{URL}/v2/custom-metrics/{CUSTOM_METRIC_ID}',
|
|
150
|
+
json=API_RESPONSE_404,
|
|
151
|
+
status=HTTPStatus.NOT_FOUND,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
with pytest.raises(NotFound):
|
|
155
|
+
CustomMetric.get(id_=CUSTOM_METRIC_ID)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@responses.activate
|
|
159
|
+
def test_cm_from_name() -> None:
|
|
160
|
+
params = {
|
|
161
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "xyzabc"}]}',
|
|
162
|
+
'model_name': 'bank_churn',
|
|
163
|
+
'organization_name': 'fiddler_dev',
|
|
164
|
+
'project_name': 'bank_churn',
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
responses.get(
|
|
168
|
+
url=f'{URL}/v2/custom-metrics',
|
|
169
|
+
json=API_RESPONSE_FROM_NAME,
|
|
170
|
+
match=[matchers.query_param_matcher(params)],
|
|
171
|
+
)
|
|
172
|
+
responses.get(
|
|
173
|
+
url=f'{URL}/v3/models',
|
|
174
|
+
json=MODEL_API_RESPONSE_FROM_NAME,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
responses.get(
|
|
178
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
179
|
+
json=MODEL_API_RESPONSE_200,
|
|
180
|
+
)
|
|
181
|
+
cm = CustomMetric.from_name(
|
|
182
|
+
name=CUSTOM_METRIC_NAME,
|
|
183
|
+
model_name=MODEL_NAME,
|
|
184
|
+
project_name=PROJECT_NAME,
|
|
185
|
+
)
|
|
186
|
+
assert isinstance(cm, CustomMetric)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@responses.activate
|
|
190
|
+
def test_cm_from_name_not_found() -> None:
|
|
191
|
+
params = {
|
|
192
|
+
'filter': '{"condition": "AND", "rules": [{"field": "name", "operator": "equal", "value": "xyzabc"}]}',
|
|
193
|
+
'model_name': 'bank_churn',
|
|
194
|
+
'organization_name': 'fiddler_dev',
|
|
195
|
+
'project_name': 'bank_churn',
|
|
196
|
+
}
|
|
197
|
+
responses.get(
|
|
198
|
+
url=f'{URL}/v2/custom-metrics',
|
|
199
|
+
json=EMPTY_LIST_API_RESPONSE,
|
|
200
|
+
match=[matchers.query_param_matcher(params)],
|
|
201
|
+
)
|
|
202
|
+
with pytest.raises(NotFound):
|
|
203
|
+
CustomMetric.from_name(
|
|
204
|
+
name=CUSTOM_METRIC_NAME,
|
|
205
|
+
model_name=MODEL_NAME,
|
|
206
|
+
project_name=PROJECT_NAME,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@responses.activate
|
|
211
|
+
def test_cm_list_empty() -> None:
|
|
212
|
+
responses.get(
|
|
213
|
+
url=f'{URL}/v2/custom-metrics',
|
|
214
|
+
json=EMPTY_LIST_API_RESPONSE,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
responses.get(
|
|
218
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
219
|
+
json=MODEL_API_RESPONSE_200,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
assert len(list(CustomMetric.list(model_id=MODEL_ID))) == 0
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@responses.activate
|
|
226
|
+
def test_cm_list_success() -> None:
|
|
227
|
+
params = {
|
|
228
|
+
'organization_name': ORG_NAME,
|
|
229
|
+
'project_name': PROJECT_NAME,
|
|
230
|
+
'model_name': MODEL_NAME,
|
|
231
|
+
'limit': 50,
|
|
232
|
+
'offset': 0,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
responses.get(
|
|
236
|
+
url=f'{URL}/v2/custom-metrics',
|
|
237
|
+
json=LIST_API_RESPONSE,
|
|
238
|
+
match=[matchers.query_param_matcher(params)],
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
responses.get(
|
|
242
|
+
url=f'{URL}/v3/models',
|
|
243
|
+
json=MODEL_API_RESPONSE_FROM_NAME,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
responses.get(
|
|
247
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
248
|
+
json=MODEL_API_RESPONSE_200,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
for cm in CustomMetric.list(model_id=MODEL_ID):
|
|
252
|
+
assert isinstance(cm, CustomMetric)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@responses.activate
|
|
256
|
+
def test_cm_create() -> None:
|
|
257
|
+
responses.post(
|
|
258
|
+
url=f'{URL}/v2/custom-metrics',
|
|
259
|
+
json=API_RESPONSE_200,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
responses.get(
|
|
263
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
264
|
+
json=MODEL_API_RESPONSE_200,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
custom_metric = CustomMetric(
|
|
268
|
+
name=CUSTOM_METRIC_NAME,
|
|
269
|
+
model_id=MODEL_ID,
|
|
270
|
+
definition="average(\"Age\")",
|
|
271
|
+
description='meh',
|
|
272
|
+
).create()
|
|
273
|
+
|
|
274
|
+
assert isinstance(custom_metric, CustomMetric)
|
|
275
|
+
assert custom_metric.id == UUID(CUSTOM_METRIC_ID)
|
|
276
|
+
assert custom_metric.name == CUSTOM_METRIC_NAME
|
|
277
|
+
assert custom_metric.model_id
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
@responses.activate
|
|
281
|
+
def test_cm_create_conflict() -> None:
|
|
282
|
+
responses.post(
|
|
283
|
+
url=f'{URL}/v2/custom-metrics',
|
|
284
|
+
json=API_RESPONSE_409,
|
|
285
|
+
status=HTTPStatus.CONFLICT,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
responses.get(
|
|
289
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
290
|
+
json=MODEL_API_RESPONSE_200,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
with pytest.raises(Conflict):
|
|
294
|
+
CustomMetric(
|
|
295
|
+
name=CUSTOM_METRIC_NAME,
|
|
296
|
+
model_id=MODEL_ID,
|
|
297
|
+
definition="average(\"Age\")",
|
|
298
|
+
description='meh',
|
|
299
|
+
).create()
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
@responses.activate
|
|
303
|
+
def test_delete_cm() -> None:
|
|
304
|
+
responses.get(
|
|
305
|
+
url=f'{URL}/v2/custom-metrics/{CUSTOM_METRIC_ID}',
|
|
306
|
+
json=API_RESPONSE_200,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
responses.get(
|
|
310
|
+
url=f'{URL}/v3/models',
|
|
311
|
+
json=MODEL_API_RESPONSE_FROM_NAME,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
responses.get(
|
|
315
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
316
|
+
json=MODEL_API_RESPONSE_200,
|
|
317
|
+
)
|
|
318
|
+
custom_metric = CustomMetric.get(id_=CUSTOM_METRIC_ID)
|
|
319
|
+
|
|
320
|
+
responses.delete(
|
|
321
|
+
url=f'{URL}/v2/custom-metrics/{CUSTOM_METRIC_ID}',
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
custom_metric.delete()
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
@responses.activate
|
|
328
|
+
def test_delete_cm_not_found() -> None:
|
|
329
|
+
responses.get(
|
|
330
|
+
url=f'{URL}/v2/custom-metrics/{CUSTOM_METRIC_ID}',
|
|
331
|
+
json=API_RESPONSE_200,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
responses.get(
|
|
335
|
+
url=f'{URL}/v3/models',
|
|
336
|
+
json=MODEL_API_RESPONSE_FROM_NAME,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
responses.get(
|
|
340
|
+
url=f'{URL}/v3/models/{MODEL_ID}',
|
|
341
|
+
json=MODEL_API_RESPONSE_200,
|
|
342
|
+
)
|
|
343
|
+
custom_metric = CustomMetric.get(id_=CUSTOM_METRIC_ID)
|
|
344
|
+
|
|
345
|
+
responses.delete(
|
|
346
|
+
url=f'{URL}/v2/custom-metrics/{CUSTOM_METRIC_ID}',
|
|
347
|
+
json=API_RESPONSE_404,
|
|
348
|
+
status=HTTPStatus.NOT_FOUND,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
with pytest.raises(NotFound):
|
|
352
|
+
custom_metric.delete()
|
fiddler/tests/test_utils.py
CHANGED
|
@@ -6,7 +6,7 @@ import pandas as pd
|
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
8
8
|
from fiddler.schemas.server_info import Version
|
|
9
|
-
from fiddler.utils.helpers import group_by
|
|
9
|
+
from fiddler.utils.helpers import group_by, try_series_retype
|
|
10
10
|
from fiddler.utils.validations import validate_artifact_dir
|
|
11
11
|
from fiddler.utils.version import match_semver
|
|
12
12
|
|
|
@@ -66,3 +66,34 @@ def test_group_by_helper() -> None:
|
|
|
66
66
|
]
|
|
67
67
|
)
|
|
68
68
|
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_try_series_retype() -> None:
|
|
72
|
+
series = pd.Series([1, 2, 3], dtype='float')
|
|
73
|
+
series = try_series_retype(series, 'int')
|
|
74
|
+
assert series.dtype == 'int'
|
|
75
|
+
|
|
76
|
+
series = pd.Series([1, 2, None])
|
|
77
|
+
series = try_series_retype(series, 'int')
|
|
78
|
+
assert series.dtype == 'float'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_try_series_retype_str_or_unkown() -> None:
|
|
82
|
+
series = pd.Series(['HIGH', 'MEDIUM', '', None], dtype='str')
|
|
83
|
+
series = try_series_retype(series, 'str')
|
|
84
|
+
assert series.dtype == 'object'
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_try_series_retype_timestamp() -> None:
|
|
88
|
+
series = pd.Series(
|
|
89
|
+
['2023-11-12 09:15:32.23', '2023-12-11 09:15:32.45'], dtype='str'
|
|
90
|
+
)
|
|
91
|
+
series = try_series_retype(series, 'timestamp')
|
|
92
|
+
assert series.dtype == 'datetime64[ns]'
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_try_series_retype_timestamp_error() -> None:
|
|
96
|
+
series = pd.Series(['2023-11-12 09:15:32.23', None], dtype='str')
|
|
97
|
+
|
|
98
|
+
with pytest.raises(TypeError):
|
|
99
|
+
try_series_retype(series, 'timestamp')
|
fiddler/utils/helpers.py
CHANGED
|
@@ -17,7 +17,7 @@ logger = get_logger(__name__)
|
|
|
17
17
|
|
|
18
18
|
def try_series_retype(series: pd.Series, new_type: str) -> pd.DataFrame | pd.Series:
|
|
19
19
|
"""Retype series."""
|
|
20
|
-
if new_type in ['unknown', 'str']:
|
|
20
|
+
if new_type in ['unknown', 'str', 'vector']:
|
|
21
21
|
# Do not retype data
|
|
22
22
|
return series
|
|
23
23
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fiddler-client
|
|
3
|
-
Version: 3.0.0.
|
|
3
|
+
Version: 3.0.0.dev5
|
|
4
4
|
Summary: Python client for Fiddler Platform
|
|
5
5
|
Home-page: https://fiddler.ai
|
|
6
6
|
Author: Fiddler Labs
|
|
@@ -49,6 +49,10 @@ Version History
|
|
|
49
49
|
- Add percentage violation metrics for alert
|
|
50
50
|
- Support for alert revisions
|
|
51
51
|
|
|
52
|
+
### 2.4.1
|
|
53
|
+
- ### **Modifications**
|
|
54
|
+
- Fix slice query with `vector` type columns
|
|
55
|
+
|
|
52
56
|
### 2.4.0
|
|
53
57
|
- ### **New Features**
|
|
54
58
|
- Add support for segments
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
fiddler/VERSION,sha256=
|
|
2
|
-
fiddler/__init__.py,sha256=
|
|
3
|
-
fiddler/_version.py,sha256=yJge9cTI7RlcMxUwRv_9Rr7NuUL4zJTXfcamq-ObEkU,27
|
|
1
|
+
fiddler/VERSION,sha256=UQ3IJpH6gZGP-vWjehD7g68w-idDM4WCOAjN3EGl-xk,11
|
|
2
|
+
fiddler/__init__.py,sha256=VCfPx51-NUioKq0OZSKmQTq0Qd20G088BcZt4CIzmG0,3378
|
|
4
3
|
fiddler/configs.py,sha256=s8nKw_2gCEKYk8dnmRxd92J8rCl08V4vPcH0xATT4Lw,258
|
|
5
4
|
fiddler/connection.py,sha256=pYaOyyJytsljofaMyRPV-Vs_i4wHKO48BxIJMqEBxHg,5760
|
|
6
5
|
fiddler/decorators.py,sha256=tWZliQQeUGwY0rU52FO9JXuOBueQXVEJywEbrgUEw1U,1820
|
|
@@ -9,7 +8,7 @@ fiddler/version.py,sha256=8fyg3UhFpqghMpxbtYIwNcB1lhCG6yTkPBbDS7IrwxY,140
|
|
|
9
8
|
fiddler/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
9
|
fiddler/constants/alert_rule.py,sha256=cmFq-VKAlQbRKEkTtMmVNdD5R52uMI2zJai6TESFwfs,512
|
|
11
10
|
fiddler/constants/baseline.py,sha256=NhmiGf73gy2IHKKpbm64HCE4eJfbxkAPy3uk_Z-6qSo,321
|
|
12
|
-
fiddler/constants/common.py,sha256=
|
|
11
|
+
fiddler/constants/common.py,sha256=pfUe_aA3GCDJcnXxOQXyv8TEBoHePbh8nJz0GTaSDCs,543
|
|
13
12
|
fiddler/constants/dataset.py,sha256=ZxPmzycSlrKpUYShpfTDqfmz8LAebzyBtIV_dBy-pRI,126
|
|
14
13
|
fiddler/constants/events.py,sha256=3SgjNo4IS-_Nod8wbj98di4B4GctF9R414MZxfQ4MkU,114
|
|
15
14
|
fiddler/constants/job.py,sha256=tMT0vr3x3IiCTQcifP2s1-VWC5gskflKexfU_VfDIzA,233
|
|
@@ -21,12 +20,13 @@ fiddler/entities/alert_record.py,sha256=RcDACWDNpntkiId-JpkLQvVeIbuaZAzn6AWl2zYI
|
|
|
21
20
|
fiddler/entities/alert_rule.py,sha256=hdIJ6n2lTCPRRTdyf-x9yVDjCaYlgYzu0jxa7iBbQkc,11908
|
|
22
21
|
fiddler/entities/base.py,sha256=YCTLt1ta8UbD7u-5BW7v_ocA4S7LevEncI5XPS_SB60,2106
|
|
23
22
|
fiddler/entities/baseline.py,sha256=1y2bFIapzlDSBd4EUfNy6e-Q8fm3t0AGAZTdiz97hXQ,8157
|
|
23
|
+
fiddler/entities/custom_metric.py,sha256=Oxcnx-o1D4WowDIa5nclGDbw5eYwpemlIyhDhjyq0Ow,6802
|
|
24
24
|
fiddler/entities/dataset.py,sha256=dmOWae2IxwoIbIRX62fCtjr6uNrht3mSuFw_QTnvZwI,4712
|
|
25
25
|
fiddler/entities/events.py,sha256=usFxs8Cq0ds1MIrOjZT5jVt3XDXMdGYakOoNFnTFQ8Y,4370
|
|
26
|
-
fiddler/entities/file.py,sha256=
|
|
26
|
+
fiddler/entities/file.py,sha256=U8IlMYl2iOdGwRWSCYmVbvFlx3rVJM-Xxr0soqLux0U,4667
|
|
27
27
|
fiddler/entities/job.py,sha256=Feiqo6ns4bRcp2uaV-kuGYAKs90-aYXvzqqi1yLivYE,5220
|
|
28
28
|
fiddler/entities/model.py,sha256=TiI-n6TfFP8gdML_kbrowBotFIsRqb2UmiClkyzXn3c,16499
|
|
29
|
-
fiddler/entities/model_artifact.py,sha256=
|
|
29
|
+
fiddler/entities/model_artifact.py,sha256=ktyFkg-nUPtdpSUGNXHfLOwSMiBaaRkdU0s9DQ67lLs,5514
|
|
30
30
|
fiddler/entities/model_deployment.py,sha256=JefFd7uUgPaxWhtVTJZqTMCLWz_18DM8o2zZmY_Hn6c,3757
|
|
31
31
|
fiddler/entities/organization.py,sha256=XvUAdBUOYXzdmblxIs4hi0mAg45NtAwy5DBaMiqi47o,1074
|
|
32
32
|
fiddler/entities/project.py,sha256=_ONa4srk6zrDl6o6-BznmjiINn7TDabYSsWxve7BZxw,4595
|
|
@@ -35,7 +35,7 @@ fiddler/entities/user.py,sha256=ev_Xx9QHAdEHYzNDafzQihXOcD8ME5XkpKgc8MiqCnw,1243
|
|
|
35
35
|
fiddler/entities/webhook.py,sha256=I-mcl92Tg2-oUUqNMOeDPBe0XawVYhNcTGXHBway7_A,3798
|
|
36
36
|
fiddler/entities/xai.py,sha256=t5LOOWRtr0KnNJHOPfdhrH1WdNT6MBpAZoQ8Teiu9a8,20232
|
|
37
37
|
fiddler/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
fiddler/libs/http_client.py,sha256=
|
|
38
|
+
fiddler/libs/http_client.py,sha256=bl2V-q66NoPHm950CiDqOoF-kCPztYWUYNy9hVUsbqg,6027
|
|
39
39
|
fiddler/libs/json_encoder.py,sha256=brsrWySvtZdaBArIkqKM5WwJUbvZf6ZbKozn1CewjOc,512
|
|
40
40
|
fiddler/libs/semver.py,sha256=3HbXG1S-ABIxL3E0FHSm5OR_YrhYtCB2Q3XJ8-tywts,15995
|
|
41
41
|
fiddler/packtools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -49,6 +49,7 @@ fiddler/schemas/alert_rule.py,sha256=-V0AibEImrfcEZfJ4J_Ed5SuZISOGsk-nIoVlX5mOOg
|
|
|
49
49
|
fiddler/schemas/base.py,sha256=upzAmneEz169h_w-UDH_tY0Abo7DeK68YOZ5qVwIMa8,189
|
|
50
50
|
fiddler/schemas/baseline.py,sha256=0z7ohzDmUKENmlVZDFx4vB-0SRVTOKaeM1N-pDSCIDk,923
|
|
51
51
|
fiddler/schemas/custom_features.py,sha256=G0UqikCyvhnLg6oUAutvq4mEsGgVcLkPlJaMCbRZj68,5382
|
|
52
|
+
fiddler/schemas/custom_metric.py,sha256=SEadAmmBxHHQV9z2gCvbY19zJfLel_tpEiy1jJTjt7s,475
|
|
52
53
|
fiddler/schemas/dataset.py,sha256=rGmpMrMfPLSs9d3_sxDTjrKqWp-o-bCe9pf_nlYyHfw,657
|
|
53
54
|
fiddler/schemas/events.py,sha256=dH6SGPBO_rgGZetIhSo4Fq0L1pTU7TEKR7zW7gg3fnI,409
|
|
54
55
|
fiddler/schemas/file.py,sha256=z_7bOxKbwQsgI8F7MMQvC6RE5dgdzYCMyD5XcBirjCc,462
|
|
@@ -73,12 +74,13 @@ fiddler/tests/constants.py,sha256=-_uoidMv6eQ-ldHCN5u_uBXuX3aS4YuylaUSbBfGHYY,10
|
|
|
73
74
|
fiddler/tests/test_connection.py,sha256=d8WoB0QRZEObWfeRAZRXRm1kw9wfEysmeo4Bld7x8js,1865
|
|
74
75
|
fiddler/tests/test_json_encoder.py,sha256=GJeFT5tTA4RTfZn1q2xm1V5SEj5DNsW3LeHPVfFxcFw,783
|
|
75
76
|
fiddler/tests/test_logger.py,sha256=StDWgtVoBOplRsvcH44Su-ikOWcafT29Kof-K-jiTxc,312
|
|
76
|
-
fiddler/tests/test_utils.py,sha256=
|
|
77
|
+
fiddler/tests/test_utils.py,sha256=AF6y7UfboEkCa-nNw0aF30SdHC7yW2Hh78J4H_4s78k,3333
|
|
77
78
|
fiddler/tests/utils.py,sha256=FEDbASW4pYZktdEK2FLnIDyZCwBzpb60m6EzkvOkwSc,335
|
|
78
79
|
fiddler/tests/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
80
|
fiddler/tests/apis/test_alert_record.py,sha256=_0EBRDn87TqTiO1KYEHKQQVtVZjj4lYjbt8Ix-RRTSg,3118
|
|
80
81
|
fiddler/tests/apis/test_alert_rule.py,sha256=wBZVU4pwPLS3QJMbO06k9DsyJJb5hI4SxPqU0RjOIWM,11197
|
|
81
82
|
fiddler/tests/apis/test_baseline.py,sha256=6KRXol1AxVwyfGH9epTGd_U4_5b-IVU4ArTWRbuJ0nc,7580
|
|
83
|
+
fiddler/tests/apis/test_custom_metric.py,sha256=I2-CqEScMOaGJsQ-jZmZlzfh35OtilJqzk6RXH3UR6A,8942
|
|
82
84
|
fiddler/tests/apis/test_dataset.py,sha256=k-H2o1txgxN0kmsHNAC5ZYqB3atPM2Vlx3TwqcTZrcw,4765
|
|
83
85
|
fiddler/tests/apis/test_events.py,sha256=e5sd3dIfMPyHoX-jX1QjCP90D-2ijJq1NERGbbfmSls,4510
|
|
84
86
|
fiddler/tests/apis/test_files.py,sha256=-BisPck7bHMSW3N40ffdQJe027Qe3079tjTlU2OI9DU,4501
|
|
@@ -93,13 +95,13 @@ fiddler/tests/apis/test_project.py,sha256=IEYT3imD4dZJg-OT888G4jQJ_AxxHN5_VkCHcm
|
|
|
93
95
|
fiddler/tests/apis/test_webhook.py,sha256=DTaEI9r2lossAaXb3b1CX4C8L3bYAzZmLIWH8VeauUs,6440
|
|
94
96
|
fiddler/tests/apis/test_xai.py,sha256=5TzRv3jSTn2xi3qpwPyKyybEVjHcSyszSHTLzuXU30s,28537
|
|
95
97
|
fiddler/utils/__init__.py,sha256=ooAJR6_tVaF6UKZriz5ynZPj8IeCzaDIPKV23F-e4Fk,53
|
|
96
|
-
fiddler/utils/helpers.py,sha256=
|
|
98
|
+
fiddler/utils/helpers.py,sha256=Xl_T_se9SOeMTmVJAOVzzmkekUsmpFMlAb2KvPCWfTw,2908
|
|
97
99
|
fiddler/utils/logger.py,sha256=FdJ3LkS9dbRjWsw5oJmNNsd7q0XRVEIvx5-TWys7L0k,669
|
|
98
100
|
fiddler/utils/model_generator.py,sha256=TwQMQDpy-0gcq6HyL68s37N-sk_nGPq33mmppK6i7hI,2203
|
|
99
101
|
fiddler/utils/validations.py,sha256=i8NtgrpCsitq6BPa5lygpKDh07oaOXu7PAlCIcMvqzY,408
|
|
100
102
|
fiddler/utils/version.py,sha256=iC8Ry7UFl9EJW_xU1WbzO_l4yK6V7eQ6U5exB3xT864,531
|
|
101
|
-
fiddler_client-3.0.0.
|
|
102
|
-
fiddler_client-3.0.0.
|
|
103
|
-
fiddler_client-3.0.0.
|
|
104
|
-
fiddler_client-3.0.0.
|
|
105
|
-
fiddler_client-3.0.0.
|
|
103
|
+
fiddler_client-3.0.0.dev5.dist-info/LICENSE.txt,sha256=w8-LUAb_VLBWSsCNmih0pAqLIicJfGu8OJXpDjkIg_o,559
|
|
104
|
+
fiddler_client-3.0.0.dev5.dist-info/METADATA,sha256=iyTcPoK3ebTms6F_Tmm3csGfUcmxgy-Ced_ASIAg4s4,20679
|
|
105
|
+
fiddler_client-3.0.0.dev5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
106
|
+
fiddler_client-3.0.0.dev5.dist-info/top_level.txt,sha256=ndC6LqvKmrTTs8czRlBOYdYgSqZbHuMf0zHt_HWpzzk,8
|
|
107
|
+
fiddler_client-3.0.0.dev5.dist-info/RECORD,,
|
fiddler/_version.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '3.0.0.dev3'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|