fiddler-client 2.3.0.dev2__py3-none-any.whl → 2.4.0.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. fiddler/__init__.py +2 -0
  2. fiddler/_version.py +1 -1
  3. fiddler/api/alert_mixin.py +1 -1
  4. fiddler/api/api.py +2 -0
  5. fiddler/api/webhooks_mixin.py +9 -7
  6. fiddler/core_objects.py +98 -47
  7. fiddler/schemas/custom_features.py +25 -19
  8. fiddler3/constants/baseline.py +19 -0
  9. fiddler3/constants/common.py +12 -0
  10. fiddler3/constants/dataset.py +7 -0
  11. fiddler3/constants/model_deployment.py +15 -0
  12. fiddler3/constants/xai.py +11 -0
  13. fiddler3/entities/__init__.py +5 -1
  14. fiddler3/entities/base.py +22 -18
  15. fiddler3/entities/baseline.py +228 -0
  16. fiddler3/entities/dataset.py +149 -0
  17. fiddler3/entities/job.py +9 -8
  18. fiddler3/entities/model.py +160 -29
  19. fiddler3/entities/model_artifact.py +350 -0
  20. fiddler3/entities/model_deployment.py +112 -0
  21. fiddler3/entities/model_surrogate.py +92 -0
  22. fiddler3/entities/organization.py +38 -0
  23. fiddler3/entities/project.py +69 -8
  24. fiddler3/entities/user.py +45 -0
  25. fiddler3/entities/xai.py +309 -0
  26. fiddler3/libs/http_client.py +24 -13
  27. fiddler3/libs/json_encoder.py +12 -0
  28. fiddler3/schemas/__init__.py +4 -0
  29. fiddler3/schemas/baseline.py +37 -0
  30. fiddler3/schemas/custom_features.py +23 -18
  31. fiddler3/schemas/dataset.py +27 -0
  32. fiddler3/schemas/deployment_params.py +25 -0
  33. fiddler3/schemas/filter_query.py +54 -0
  34. fiddler3/schemas/job.py +2 -2
  35. fiddler3/schemas/model.py +9 -9
  36. fiddler3/schemas/model_artifact.py +6 -0
  37. fiddler3/schemas/model_deployment.py +26 -0
  38. fiddler3/schemas/organization.py +9 -1
  39. fiddler3/schemas/project.py +4 -4
  40. fiddler3/schemas/server_info.py +2 -2
  41. fiddler3/schemas/user.py +1 -1
  42. fiddler3/schemas/xai.py +32 -0
  43. fiddler3/tests/apis/test_baseline.py +292 -0
  44. fiddler3/tests/apis/test_dataset.py +173 -0
  45. fiddler3/tests/apis/test_mixin.py +77 -0
  46. fiddler3/tests/apis/test_model.py +102 -7
  47. fiddler3/tests/apis/test_model_artifact.py +175 -0
  48. fiddler3/tests/apis/test_model_deployment.py +98 -0
  49. fiddler3/tests/apis/test_model_surrogate.py +159 -0
  50. fiddler3/tests/apis/test_project.py +36 -20
  51. fiddler3/tests/apis/test_xai.py +690 -0
  52. fiddler3/tests/constants.py +10 -0
  53. fiddler3/tests/test_json_encoder.py +16 -0
  54. fiddler3/tests/test_logger.py +12 -0
  55. fiddler3/tests/test_utils.py +19 -0
  56. fiddler3/utils/__init__.py +1 -0
  57. fiddler3/utils/helpers.py +43 -0
  58. fiddler3/utils/logger.py +15 -0
  59. fiddler3/utils/validations.py +11 -0
  60. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/METADATA +7 -5
  61. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/RECORD +65 -33
  62. tests/fiddler/test_segments.py +227 -0
  63. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/LICENSE.txt +0 -0
  64. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/WHEEL +0 -0
  65. {fiddler_client-2.3.0.dev2.dist-info → fiddler_client-2.4.0.dev1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,228 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Iterator
6
+ from uuid import UUID
7
+
8
+ from fiddler3.constants.dataset import EnvType
9
+ from fiddler3.decorators import handle_api_error
10
+ from fiddler3.entities.base import BaseEntity
11
+ from fiddler3.entities.dataset import DatasetCompactMixin
12
+ from fiddler3.entities.helpers import raise_not_found
13
+ from fiddler3.entities.model import ModelCompactMixin
14
+ from fiddler3.entities.project import ProjectCompactMixin
15
+ from fiddler3.schemas.baseline import BaselineResp
16
+ from fiddler3.schemas.filter_query import OperatorType, QueryCondition, QueryRule
17
+
18
+
19
+ class Baseline(
20
+ BaseEntity, ModelCompactMixin, ProjectCompactMixin, DatasetCompactMixin
21
+ ): # pylint: disable=too-many-instance-attributes
22
+ def __init__( # pylint: disable=too-many-arguments
23
+ self,
24
+ name: str,
25
+ model_id: UUID,
26
+ environment: EnvType,
27
+ type_: str,
28
+ dataset_id: UUID | None = None,
29
+ start_time: int | None = None,
30
+ end_time: int | None = None,
31
+ offset: int | None = None,
32
+ window_size: int | None = None,
33
+ ) -> None:
34
+ """Construct a baseline instance."""
35
+ self.name = name
36
+ self.model_id = model_id
37
+ self.type = type_
38
+ self.environment = environment
39
+ self.dataset_id = dataset_id
40
+ self.start_time = start_time
41
+ self.end_time = end_time
42
+ self.offset = offset
43
+ self.window_size = window_size
44
+
45
+ self.id: UUID | None = None
46
+ self.row_count: int | None = None
47
+ self.project_id: UUID | None = None
48
+ self.create_at: datetime | None = None
49
+ self.updated_at: datetime | None = None
50
+
51
+ # Deserialized response object
52
+ self._resp: BaselineResp | None = None
53
+
54
+ @staticmethod
55
+ def _get_url(id_: UUID | str | None = None) -> str:
56
+ """Get model resource/item url."""
57
+ url = '/v3/baselines'
58
+ return url if not id_ else f'{url}/{id_}'
59
+
60
+ @classmethod
61
+ def _from_dict(cls, data: dict) -> Baseline:
62
+ """Build entity object from the given dictionary."""
63
+
64
+ # Deserialize the response
65
+ resp_obj = BaselineResp(**data)
66
+
67
+ # Initialize
68
+ instance = cls(
69
+ name=resp_obj.name,
70
+ model_id=resp_obj.model.id,
71
+ environment=resp_obj.dataset.type,
72
+ dataset_id=resp_obj.dataset.id,
73
+ type_=resp_obj.type,
74
+ start_time=resp_obj.start_time,
75
+ end_time=resp_obj.end_time,
76
+ offset=resp_obj.offset,
77
+ window_size=resp_obj.window_size,
78
+ )
79
+
80
+ # Add remaining fields
81
+ fields = [
82
+ 'id',
83
+ 'created_at',
84
+ 'updated_at',
85
+ 'row_count',
86
+ ]
87
+ for field in fields:
88
+ setattr(instance, field, getattr(resp_obj, field, None))
89
+
90
+ instance.project_id = resp_obj.project.id
91
+ instance._resp = resp_obj
92
+
93
+ return instance
94
+
95
+ def _refresh(self, data: dict) -> None:
96
+ """Refresh the fields of this instance from the given response dictionary"""
97
+ # Deserialize the response
98
+ resp_obj = BaselineResp(**data)
99
+
100
+ # Reset properties
101
+ self.model_id = resp_obj.model.id
102
+ self.environment = resp_obj.dataset.type
103
+ self.dataset_id = resp_obj.dataset.id
104
+
105
+ # Add remaining fields
106
+ fields = [
107
+ 'id',
108
+ 'name',
109
+ 'type',
110
+ 'start_time',
111
+ 'end_time',
112
+ 'offset',
113
+ 'window_size',
114
+ 'created_at',
115
+ 'updated_at',
116
+ 'row_count',
117
+ ]
118
+ for field in fields:
119
+ setattr(self, field, getattr(resp_obj, field, None))
120
+
121
+ self._resp = resp_obj
122
+
123
+ @classmethod
124
+ @handle_api_error
125
+ def get(cls, id_: UUID | str) -> Baseline:
126
+ """
127
+ Get the baseline instance using baseline id.
128
+
129
+ :param id_: unique uuid format identifier for baseline
130
+ :return: baseline instance
131
+ """
132
+ response = cls._client().get(url=cls._get_url(id_=id_))
133
+ return cls._from_response(response=response)
134
+
135
+ @classmethod
136
+ @handle_api_error
137
+ def from_name(cls, name: str, model_name: str, project_name: str) -> Baseline:
138
+ """
139
+ Get the baseline instance using baseline name, model name and project name.
140
+
141
+ :param name: baseline name
142
+ :param model_name: name of the model associated with the baseline
143
+ :param project_name: name of the project associated with the baseline
144
+ :return: Baseline instance for the provided params
145
+ """
146
+
147
+ _filter = QueryCondition(
148
+ rules=[
149
+ QueryRule(field='name', operator=OperatorType.EQUAL, value=name),
150
+ QueryRule(
151
+ field='project_name',
152
+ operator=OperatorType.EQUAL,
153
+ value=project_name,
154
+ ),
155
+ QueryRule(
156
+ field='model_name', operator=OperatorType.EQUAL, value=model_name
157
+ ),
158
+ ]
159
+ )
160
+
161
+ response = cls._client().get(
162
+ url=cls._get_url(),
163
+ params={'filter': _filter.json()},
164
+ )
165
+ if response.json()['data']['total'] == 0:
166
+ raise_not_found('Baseline not found for the given identifier')
167
+
168
+ return cls._from_dict(data=response.json()['data']['items'][0])
169
+
170
+ @classmethod
171
+ @handle_api_error
172
+ def list(cls) -> Iterator[Baseline]:
173
+ """Get a list of all baselines in the organization."""
174
+ params: dict[str, Any] = {}
175
+
176
+ for baseline in cls._paginate(url=cls._get_url(), params=params):
177
+ yield cls._from_dict(data=baseline)
178
+
179
+ @handle_api_error
180
+ def create(self) -> Baseline:
181
+ """Create a new baseline."""
182
+ response = self._client().post(
183
+ url=self._get_url(),
184
+ data={
185
+ 'name': self.name,
186
+ 'model_id': self.model_id,
187
+ 'type': self.type,
188
+ 'env_type': self.environment,
189
+ 'start_time': self.start_time,
190
+ 'end_time': self.end_time,
191
+ 'offset': self.offset,
192
+ 'window_size': self.window_size,
193
+ 'env_id': self.dataset_id,
194
+ },
195
+ )
196
+ self._refresh_from_response(response=response)
197
+ return self
198
+
199
+ @handle_api_error
200
+ def delete(self) -> None:
201
+ """Delete a baseline."""
202
+ assert self.id is not None
203
+
204
+ self._client().delete(url=self._get_url(id_=self.id))
205
+
206
+
207
+ @dataclass
208
+ class BaselineCompact:
209
+ id: UUID
210
+ name: str
211
+
212
+ def fetch(self) -> Baseline:
213
+ """Fetch baseline instance"""
214
+ return Baseline.get(id_=self.id)
215
+
216
+
217
+ class BaselineCompactMixin:
218
+ @property
219
+ def baseline(self) -> BaselineCompact:
220
+ """Baseline instance"""
221
+ response = getattr(self, '_resp', None)
222
+ if not response or not hasattr(response, 'baseline'):
223
+ raise AttributeError(
224
+ 'This property is available only for objects generated from API '
225
+ 'response.'
226
+ )
227
+
228
+ return BaselineCompact(id=response.baseline.id, name=response.baseline.name)
@@ -0,0 +1,149 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Iterator
5
+ from uuid import UUID
6
+
7
+ from fiddler3.constants.dataset import EnvType
8
+ from fiddler3.decorators import handle_api_error
9
+ from fiddler3.entities.base import BaseEntity
10
+ from fiddler3.entities.helpers import raise_not_found
11
+ from fiddler3.entities.project import ProjectCompactMixin
12
+ from fiddler3.schemas.dataset import DatasetResp
13
+ from fiddler3.schemas.filter_query import OperatorType, QueryCondition, QueryRule
14
+
15
+
16
+ class Dataset(BaseEntity, ProjectCompactMixin):
17
+ def __init__(self, name: str, model_id: str | UUID, project_id: UUID | str) -> None:
18
+ """Construct a dataset instance."""
19
+ self.model_id = model_id
20
+ self.project_id = project_id
21
+ self.name = name
22
+ self.row_count: int | None = None
23
+
24
+ self.id: UUID | None = None # pylint: disable=invalid-name
25
+
26
+ # Deserialized response object
27
+ self._resp: DatasetResp | None = None
28
+
29
+ @staticmethod
30
+ def _get_url(id_: UUID | str | None = None) -> str:
31
+ """Get model resource/item url."""
32
+ url = '/v3/environments'
33
+ return url if not id_ else f'{url}/{id_}'
34
+
35
+ @classmethod
36
+ def _from_dict(cls, data: dict) -> Dataset:
37
+ """Build entity object from the given dictionary."""
38
+
39
+ # Deserialize the response
40
+ resp_obj = DatasetResp(**data)
41
+
42
+ # Initialize
43
+ instance = cls(
44
+ name=resp_obj.name,
45
+ model_id=resp_obj.model.id,
46
+ project_id=resp_obj.project.id,
47
+ )
48
+
49
+ # Add remaining fields
50
+ fields = [
51
+ 'id',
52
+ 'row_count',
53
+ ]
54
+ for field in fields:
55
+ setattr(instance, field, getattr(resp_obj, field, None))
56
+
57
+ instance._resp = resp_obj
58
+
59
+ return instance
60
+
61
+ @classmethod
62
+ @handle_api_error
63
+ def get(cls, id_: UUID | str) -> Dataset:
64
+ """
65
+ Get the dataset instance using dataset id.
66
+
67
+ :param id_: unique uuid format identifier for dataset
68
+ :return: dataset instance
69
+ """
70
+ response = cls._client().get(url=cls._get_url(id_=id_))
71
+ return cls._from_response(response=response)
72
+
73
+ @classmethod
74
+ @handle_api_error
75
+ def from_name(cls, name: str, model_name: str, project_name: str) -> Dataset:
76
+ """
77
+ Get the dataset instance using dataset name.
78
+
79
+ :param name: Dataset name
80
+ :param model_name: Name of the model associated with the dataset
81
+ :param project_name: name of the project associated with the dataset
82
+ :return: Dataset instance for the provided params
83
+ """
84
+ _filter = QueryCondition(
85
+ rules=[
86
+ QueryRule(field='name', operator=OperatorType.EQUAL, value=name),
87
+ QueryRule(
88
+ field='project_name',
89
+ operator=OperatorType.EQUAL,
90
+ value=project_name,
91
+ ),
92
+ QueryRule(
93
+ field='model_name', operator=OperatorType.EQUAL, value=model_name
94
+ ),
95
+ ]
96
+ )
97
+
98
+ response = cls._client().get(
99
+ url=cls._get_url(),
100
+ params={'filter': _filter.json()},
101
+ )
102
+
103
+ if response.json()['data']['total'] == 0:
104
+ raise_not_found('Dataset not found for the given identifier')
105
+
106
+ return cls._from_dict(data=response.json()['data']['items'][0])
107
+
108
+ @classmethod
109
+ @handle_api_error
110
+ def list(cls, model_id: UUID | str | None = None) -> Iterator[Dataset]:
111
+ """
112
+ Get a list of all datasets in the organization.
113
+
114
+ :param model_id: unique uuid format identifier for model
115
+ :return: Iterator of datasets
116
+ """
117
+ params: dict[str, Any] = {'type': EnvType.PRE_PRODUCTION.value}
118
+ if model_id:
119
+ params['model_id'] = str(model_id)
120
+
121
+ for dataset in cls._paginate(url=cls._get_url(), params=params):
122
+ yield cls._from_dict(data=dataset)
123
+
124
+
125
+ @dataclass
126
+ class DatasetCompact:
127
+ id: UUID
128
+ name: str
129
+
130
+ def fetch(self) -> Dataset:
131
+ """Fetch dataset instance"""
132
+ return Dataset.get(id_=self.id)
133
+
134
+
135
+ class DatasetCompactMixin:
136
+ @property
137
+ def dataset(self) -> DatasetCompact | None:
138
+ """Dataset instance"""
139
+ response = getattr(self, '_resp', None)
140
+ if not response or not hasattr(response, 'dataset'):
141
+ raise AttributeError(
142
+ 'This property is available only for objects generated from API '
143
+ 'response.'
144
+ )
145
+
146
+ if response.dataset.type == EnvType.PRODUCTION:
147
+ return None
148
+
149
+ return DatasetCompact(id=response.dataset.id, name=response.dataset.name)
fiddler3/entities/job.py CHANGED
@@ -9,17 +9,15 @@ from fiddler3.constants.job import JobStatus
9
9
  from fiddler3.decorators import handle_api_error
10
10
  from fiddler3.entities.base import BaseEntity
11
11
  from fiddler3.exceptions import AsyncJobFailed
12
- from fiddler3.schemas.job import JobResponse
12
+ from fiddler3.schemas.job import JobResp
13
13
  from fiddler3.utils.logger import get_logger
14
14
 
15
15
  logger = get_logger(__name__)
16
16
 
17
17
 
18
- class Job(BaseEntity):
18
+ class Job(BaseEntity): # pylint: disable=too-many-instance-attributes
19
19
  def __init__(self) -> None:
20
- """
21
- Construct a job instance
22
- """
20
+ """Construct a job instance"""
23
21
  self.name: str | None = None
24
22
  self.status: str | None = None
25
23
  self.progress: float | None = None
@@ -31,14 +29,14 @@ class Job(BaseEntity):
31
29
  self.id: UUID | None = None
32
30
 
33
31
  # Deserialized response object
34
- self._resp: JobResponse | None = None
32
+ self._resp: JobResp | None = None
35
33
 
36
34
  @classmethod
37
35
  def _from_dict(cls, data: dict) -> Job:
38
36
  """Build entity object from the given dictionary"""
39
37
 
40
38
  # Deserialize the response
41
- resp_obj = JobResponse(**data)
39
+ resp_obj = JobResp(**data)
42
40
 
43
41
  # Initialize
44
42
  instance = cls()
@@ -72,7 +70,8 @@ class Job(BaseEntity):
72
70
  def get(cls, id_: UUID | str, verbose: bool = False) -> Job:
73
71
  """
74
72
  Get the job instance using job id
75
- :params id: Unique identifier of the job
73
+
74
+ :param id_: Unique identifier of the job
76
75
  :param verbose: flag to get extra details about the tasks executed
77
76
  :return: single job object for the input params
78
77
  """
@@ -86,6 +85,7 @@ class Job(BaseEntity):
86
85
  ) -> Iterator[Job]:
87
86
  """
88
87
  Watch job status at given interval and yield job object
88
+
89
89
  :param interval: Interval in seconds between polling for job status
90
90
  :param timeout: Timeout in seconds for iterator to stop.
91
91
  :return: Iterator of job objects
@@ -123,6 +123,7 @@ class Job(BaseEntity):
123
123
  ) -> None:
124
124
  """
125
125
  Wait for job to complete either with success or failure status
126
+
126
127
  :param interval: Interval in seconds between polling for job status
127
128
  :param timeout: Timeout in seconds for iterator to stop.
128
129
  """