fiddler-client 3.1.0.dev1__tar.gz → 3.1.0.dev3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. fiddler-client-3.1.0.dev3/PKG-INFO +46 -0
  2. fiddler-client-3.1.0.dev3/PUBLIC.md +22 -0
  3. fiddler-client-3.1.0.dev3/fiddler/VERSION +1 -0
  4. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/__init__.py +2 -0
  5. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/alert_rule.py +5 -1
  6. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/events.py +51 -16
  7. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/model.py +29 -11
  8. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/webhook.py +18 -0
  9. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/alert_rule.py +3 -2
  10. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/custom_expression.py +7 -0
  11. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/custom_features.py +30 -29
  12. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/model.py +1 -0
  13. fiddler-client-3.1.0.dev3/fiddler/schemas/model_spec.py +32 -0
  14. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_alert_rule.py +44 -37
  15. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_mixin.py +4 -1
  16. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_model.py +7 -0
  17. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_webhook.py +57 -0
  18. fiddler-client-3.1.0.dev3/fiddler_client.egg-info/PKG-INFO +46 -0
  19. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler_client.egg-info/requires.txt +1 -0
  20. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/setup.py +1 -0
  21. fiddler-client-3.1.0.dev1/PKG-INFO +0 -538
  22. fiddler-client-3.1.0.dev1/PUBLIC.md +0 -515
  23. fiddler-client-3.1.0.dev1/fiddler/VERSION +0 -1
  24. fiddler-client-3.1.0.dev1/fiddler/schemas/model_spec.py +0 -30
  25. fiddler-client-3.1.0.dev1/fiddler_client.egg-info/PKG-INFO +0 -538
  26. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/LICENSE.txt +0 -0
  27. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/MANIFEST.in +0 -0
  28. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/README.md +0 -0
  29. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/configs.py +0 -0
  30. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/connection.py +0 -0
  31. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/__init__.py +0 -0
  32. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/alert_rule.py +0 -0
  33. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/baseline.py +0 -0
  34. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/common.py +0 -0
  35. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/dataset.py +0 -0
  36. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/events.py +0 -0
  37. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/job.py +0 -0
  38. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/model.py +0 -0
  39. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/model_deployment.py +0 -0
  40. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/constants/xai.py +0 -0
  41. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/decorators.py +0 -0
  42. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/__init__.py +0 -0
  43. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/alert_record.py +0 -0
  44. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/base.py +0 -0
  45. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/baseline.py +0 -0
  46. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/custom_expression.py +0 -0
  47. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/dataset.py +0 -0
  48. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/file.py +0 -0
  49. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/job.py +0 -0
  50. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/model_artifact.py +0 -0
  51. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/model_deployment.py +0 -0
  52. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/organization.py +0 -0
  53. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/project.py +0 -0
  54. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/surrogate.py +0 -0
  55. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/user.py +0 -0
  56. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/entities/xai.py +0 -0
  57. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/exceptions.py +0 -0
  58. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/libs/__init__.py +0 -0
  59. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/libs/http_client.py +0 -0
  60. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/libs/json_encoder.py +0 -0
  61. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/libs/semver.py +0 -0
  62. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/packtools/__init__.py +0 -0
  63. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/packtools/gem.py +0 -0
  64. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/packtools/keras_ig_helpers.py +0 -0
  65. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/packtools/project_attributions_helpers.py +0 -0
  66. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/packtools/template_model.py +0 -0
  67. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/__init__.py +0 -0
  68. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/alert_record.py +0 -0
  69. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/base.py +0 -0
  70. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/baseline.py +0 -0
  71. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/dataset.py +0 -0
  72. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/events.py +0 -0
  73. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/file.py +0 -0
  74. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/filter_query.py +0 -0
  75. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/job.py +0 -0
  76. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/model_deployment.py +0 -0
  77. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/model_schema.py +0 -0
  78. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/model_task_params.py +0 -0
  79. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/organization.py +0 -0
  80. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/project.py +0 -0
  81. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/response.py +0 -0
  82. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/server_info.py +0 -0
  83. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/user.py +0 -0
  84. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/webhook.py +0 -0
  85. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/xai.py +0 -0
  86. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/schemas/xai_params.py +0 -0
  87. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/__init__.py +0 -0
  88. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/__init__.py +0 -0
  89. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_alert_record.py +0 -0
  90. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_baseline.py +0 -0
  91. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_custom_metric.py +0 -0
  92. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_dataset.py +0 -0
  93. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_events.py +0 -0
  94. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_files.py +0 -0
  95. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_generate_model.py +0 -0
  96. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_job.py +0 -0
  97. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_model_artifact.py +0 -0
  98. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_model_deployment.py +0 -0
  99. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_model_surrogate.py +0 -0
  100. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_project.py +0 -0
  101. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_segment.py +0 -0
  102. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/apis/test_xai.py +0 -0
  103. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/conftest.py +0 -0
  104. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/constants.py +0 -0
  105. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/test_connection.py +0 -0
  106. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/test_json_encoder.py +0 -0
  107. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/test_logger.py +0 -0
  108. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/test_utils.py +0 -0
  109. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/tests/utils.py +0 -0
  110. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/utils/__init__.py +0 -0
  111. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/utils/helpers.py +0 -0
  112. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/utils/logger.py +0 -0
  113. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/utils/model_generator.py +0 -0
  114. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/utils/validations.py +0 -0
  115. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/utils/version.py +0 -0
  116. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler/version.py +0 -0
  117. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler_client.egg-info/SOURCES.txt +0 -0
  118. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler_client.egg-info/dependency_links.txt +0 -0
  119. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/fiddler_client.egg-info/top_level.txt +0 -0
  120. {fiddler-client-3.1.0.dev1 → fiddler-client-3.1.0.dev3}/setup.cfg +0 -0
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.1
2
+ Name: fiddler-client
3
+ Version: 3.1.0.dev3
4
+ Summary: Python client for Fiddler Platform
5
+ Home-page: https://fiddler.ai
6
+ Author: Fiddler Labs
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >3.8.0
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE.txt
13
+ Requires-Dist: pip>=21.0
14
+ Requires-Dist: requests<3
15
+ Requires-Dist: requests-toolbelt
16
+ Requires-Dist: pandas>=1.2.5
17
+ Requires-Dist: pydantic<2,>=1.9.0
18
+ Requires-Dist: deprecated==1.2.13
19
+ Requires-Dist: tqdm
20
+ Requires-Dist: simplejson>=3.17.0
21
+ Requires-Dist: pyarrow>=7.0.0
22
+ Requires-Dist: pyyaml
23
+ Requires-Dist: typing-extensions<=4.5.0
24
+
25
+ Fiddler Client
26
+ =============
27
+
28
+ Python client for interacting with Fiddler. Provides a user-friendly interface to our REST API and enables event
29
+ publishing for use with our monitoring features.
30
+
31
+ Requirements
32
+ ------------
33
+ Requires Python >= Python-3.6.3 and pip >= 19.0
34
+
35
+ Installation
36
+ ------------
37
+
38
+ $ pip3 install fiddler-client
39
+
40
+ API Example Usage
41
+ -------------
42
+ Documentation for the API can be found [here](https://docs.fiddler.ai/reference/about-the-fiddler-client). For examples of interacting with our APIs, please check out our [Quick Start Guide](https://docs.fiddler.ai/docs/quick-start) as well as the notebooks found on our [Examples Github](https://github.com/fiddler-labs/fiddler-examples).
43
+
44
+ Version History
45
+ -------------
46
+ Version history is available on [Fiddler documentation page](https://docs.fiddler.ai/page/python-client-version-history).
@@ -0,0 +1,22 @@
1
+ Fiddler Client
2
+ =============
3
+
4
+ Python client for interacting with Fiddler. Provides a user-friendly interface to our REST API and enables event
5
+ publishing for use with our monitoring features.
6
+
7
+ Requirements
8
+ ------------
9
+ Requires Python >= Python-3.6.3 and pip >= 19.0
10
+
11
+ Installation
12
+ ------------
13
+
14
+ $ pip3 install fiddler-client
15
+
16
+ API Example Usage
17
+ -------------
18
+ Documentation for the API can be found [here](https://docs.fiddler.ai/reference/about-the-fiddler-client). For examples of interacting with our APIs, please check out our [Quick Start Guide](https://docs.fiddler.ai/docs/quick-start) as well as the notebooks found on our [Examples Github](https://github.com/fiddler-labs/fiddler-examples).
19
+
20
+ Version History
21
+ -------------
22
+ Version history is available on [Fiddler documentation page](https://docs.fiddler.ai/page/python-client-version-history).
@@ -0,0 +1 @@
1
+ 3.1.0.dev3
@@ -61,6 +61,7 @@ from fiddler.schemas.xai import ( # noqa
61
61
  SqlSliceQueryDataSource,
62
62
  )
63
63
  from fiddler.schemas.xai_params import XaiParams # noqa
64
+ from fiddler.utils.helpers import group_by # noqa
64
65
  from fiddler.utils.logger import set_logging # noqa
65
66
  from fiddler.version import __version__ # noqa
66
67
 
@@ -141,4 +142,5 @@ __all__ = [
141
142
  'ApiError',
142
143
  # Utilities
143
144
  'set_logging',
145
+ 'group_by',
144
146
  ]
@@ -34,6 +34,7 @@ class AlertRule(
34
34
  warning_threshold: float | None = None,
35
35
  columns: list[str] | None = None,
36
36
  baseline_id: UUID | str | None = None,
37
+ segment_id: UUID | str | None = None,
37
38
  compare_bin_delta: int | None = None,
38
39
  ) -> None:
39
40
  """Construct a alert rule instance."""
@@ -49,6 +50,7 @@ class AlertRule(
49
50
  self.critical_threshold = critical_threshold
50
51
  self.condition = condition
51
52
  self.bin_size = bin_size
53
+ self.segment_id = segment_id
52
54
 
53
55
  self.id: UUID | None = None
54
56
  self.project_id: UUID | None = None
@@ -84,7 +86,8 @@ class AlertRule(
84
86
  critical_threshold=resp_obj.critical_threshold,
85
87
  warning_threshold=resp_obj.warning_threshold,
86
88
  columns=resp_obj.columns,
87
- baseline_id=resp_obj.baseline_id,
89
+ baseline_id=resp_obj.baseline.id if resp_obj.baseline else None,
90
+ segment_id=resp_obj.segment.id if resp_obj.segment else None,
88
91
  compare_bin_delta=resp_obj.compare_bin_delta,
89
92
  )
90
93
 
@@ -210,6 +213,7 @@ class AlertRule(
210
213
  'compare_to': self.compare_to,
211
214
  'condition': self.condition,
212
215
  'bin_size': self.bin_size,
216
+ 'segment_id': self.segment_id,
213
217
  'critical_threshold': self.critical_threshold,
214
218
  'warning_threshold': self.warning_threshold,
215
219
  'feature_names': self.columns,
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import tempfile
4
4
  from pathlib import Path
5
- from typing import Any
5
+ from typing import Any, Callable
6
6
  from uuid import UUID
7
7
 
8
8
  import pandas as pd
@@ -17,6 +17,9 @@ from fiddler.entities.job import Job
17
17
  from fiddler.schemas.dataset import EnvType
18
18
  from fiddler.schemas.events import EventsSource, FileSource
19
19
  from fiddler.schemas.job import JobCompactResp
20
+ from fiddler.utils.logger import get_logger
21
+
22
+ logger = get_logger(__name__)
20
23
 
21
24
 
22
25
  class EventPublisher(ConnectionMixin):
@@ -51,40 +54,72 @@ class EventPublisher(ConnectionMixin):
51
54
 
52
55
  :return: list[UUID] for list of dicts source and Job object for file path or dataframe source.
53
56
  """
57
+
58
+ publish_method = self._get_publish_method(source=source)
59
+
60
+ return publish_method(
61
+ source=source,
62
+ environment=environment,
63
+ dataset_name=dataset_name,
64
+ update=update,
65
+ )
66
+
67
+ def _get_publish_method(
68
+ self, source: list[dict[str, Any]] | str | Path | pd.DataFrame
69
+ ) -> Callable:
54
70
  if isinstance(source, (str, Path)):
55
- return self._publish_file(
56
- source=source,
57
- environment=environment,
58
- dataset_name=dataset_name,
59
- update=update,
60
- )
71
+ return self._publish_file
61
72
 
62
73
  if isinstance(source, pd.DataFrame):
63
- with tempfile.NamedTemporaryFile(suffix='.csv') as temp_file:
64
- source.to_csv(temp_file.name, index=False)
74
+ return self._publish_df
75
+
76
+ if isinstance(source, list):
77
+ return self._publish_stream
78
+
79
+ raise ValueError(f'Unsupported source - {type(source)}')
80
+
81
+ def _publish_df(
82
+ self,
83
+ source: pd.DataFrame,
84
+ environment: EnvType,
85
+ dataset_name: str | None = None,
86
+ update: bool = False,
87
+ ) -> Job:
88
+ with tempfile.NamedTemporaryFile(suffix='.parquet') as temp_file:
89
+ try:
90
+ source.to_parquet(temp_file.name, index=False)
65
91
  return self._publish_file(
66
92
  source=temp_file.name,
67
93
  environment=environment,
68
94
  dataset_name=dataset_name,
69
95
  update=update,
70
96
  )
71
-
72
- elif isinstance(source, list):
73
- return self._publish_stream(source=source, update=update)
74
-
75
- raise ValueError(f'Unsupported source - {type(source)}')
97
+ except Exception:
98
+ logger.warning(
99
+ 'Failed to convert input dataframe to parquet format. Retrying as a CSV file.'
100
+ )
101
+ with tempfile.NamedTemporaryFile(suffix='.csv') as temp_file:
102
+ source.to_csv(temp_file.name, index=False)
103
+ return self._publish_file(
104
+ source=temp_file.name,
105
+ environment=environment,
106
+ dataset_name=dataset_name,
107
+ update=update,
108
+ )
76
109
 
77
110
  def _publish_stream(
78
111
  self,
79
112
  source: list[dict[str, Any]],
113
+ environment: EnvType = EnvType.PRODUCTION,
114
+ dataset_name: str | None = None,
80
115
  update: bool = False,
81
116
  ) -> list[UUID]:
82
117
  event_ids = []
83
118
  for i in tqdm(range(0, len(source), self.STREAM_LIMIT)):
84
119
  response = self._publish_call(
85
120
  source=EventsSource(events=source[i : i + self.STREAM_LIMIT]),
86
- environment=EnvType.PRODUCTION,
87
- dataset_name=None,
121
+ environment=environment,
122
+ dataset_name=dataset_name,
88
123
  update=update,
89
124
  )
90
125
  event_ids.extend(response.json()['data']['event_ids'])
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import builtins
4
- import copy
5
4
  import typing
6
5
  from dataclasses import dataclass
7
6
  from datetime import datetime
@@ -33,6 +32,7 @@ from fiddler.schemas.model_spec import ModelSpec
33
32
  from fiddler.schemas.model_task_params import ModelTaskParams
34
33
  from fiddler.schemas.xai_params import XaiParams
35
34
  from fiddler.utils.helpers import raise_not_found
35
+ from fiddler.utils.logger import get_logger
36
36
  from fiddler.utils.model_generator import ModelGenerator
37
37
 
38
38
  if typing.TYPE_CHECKING:
@@ -40,6 +40,9 @@ if typing.TYPE_CHECKING:
40
40
  from fiddler.entities.dataset import Dataset
41
41
 
42
42
 
43
+ logger = get_logger(__name__)
44
+
45
+
43
46
  class Model(
44
47
  BaseEntity,
45
48
  CreatedByMixin,
@@ -307,7 +310,9 @@ class Model(
307
310
  params = {'filter': _filter.json()}
308
311
 
309
312
  for model in cls._paginate(url=cls._get_url(), params=params):
310
- yield ModelCompact(id=model['id'], name=model['name'])
313
+ yield ModelCompact(
314
+ id=model['id'], name=model['name'], version=model['version']
315
+ )
311
316
 
312
317
  def duplicate(self, version: str | None = None) -> Model:
313
318
  """
@@ -319,13 +324,21 @@ class Model(
319
324
  :param version: Version name for the new instance
320
325
  :return: Model instance
321
326
  """
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
327
+ return Model(
328
+ name=self.name,
329
+ project_id=self.project_id,
330
+ schema=self.schema,
331
+ spec=self.spec,
332
+ version=version if version else self.version,
333
+ input_type=self.input_type,
334
+ task=self.task,
335
+ task_params=self.task_params,
336
+ description=self.description,
337
+ event_id_col=self.event_id_col,
338
+ event_ts_col=self.event_ts_col,
339
+ event_ts_format=self.event_ts_format,
340
+ xai_params=self.xai_params,
341
+ )
329
342
 
330
343
  @property
331
344
  def datasets(self) -> Iterator[Dataset]:
@@ -456,7 +469,7 @@ class Model(
456
469
  :return: list[UUID] for list of dicts or dataframe source and Job object for
457
470
  file path source.
458
471
  """
459
-
472
+ logger.info('Model[%s/%s] - Publishing events', self.name, self.version)
460
473
  return self._event_publisher.publish(
461
474
  source=source,
462
475
  environment=environment,
@@ -548,6 +561,7 @@ class Model(
548
561
  class ModelCompact:
549
562
  id: UUID
550
563
  name: str
564
+ version: str | None = None
551
565
 
552
566
  def fetch(self) -> Model:
553
567
  """Fetch model instance"""
@@ -565,4 +579,8 @@ class ModelCompactMixin:
565
579
  'response.'
566
580
  )
567
581
 
568
- return ModelCompact(id=response.model.id, name=response.model.name)
582
+ return ModelCompact(
583
+ id=response.model.id,
584
+ name=response.model.name,
585
+ version=response.model.version,
586
+ )
@@ -6,7 +6,9 @@ from uuid import UUID
6
6
 
7
7
  from fiddler.decorators import handle_api_error
8
8
  from fiddler.entities.base import BaseEntity
9
+ from fiddler.schemas.filter_query import OperatorType, QueryCondition, QueryRule
9
10
  from fiddler.schemas.webhook import WebhookProvider, WebhookResp
11
+ from fiddler.utils.helpers import raise_not_found
10
12
 
11
13
 
12
14
  class Webhook(BaseEntity):
@@ -81,6 +83,22 @@ class Webhook(BaseEntity):
81
83
  response = cls._client().get(url=cls._get_url(id_))
82
84
  return cls._from_response(response=response)
83
85
 
86
+ @classmethod
87
+ @handle_api_error
88
+ def from_name(cls, name: str) -> Webhook:
89
+ """Get the webhook instance using webhook name"""
90
+ _filter = QueryCondition(
91
+ rules=[QueryRule(field='name', operator=OperatorType.EQUAL, value=name)]
92
+ )
93
+
94
+ response = cls._client().get(
95
+ url=cls._get_url(), params={'filter': _filter.json()}
96
+ )
97
+ if response.json()['data']['total'] == 0:
98
+ raise_not_found('Webhook not found for the given identifier')
99
+
100
+ return cls._from_dict(data=response.json()['data']['items'][0])
101
+
84
102
  @classmethod
85
103
  @handle_api_error
86
104
  def list(cls) -> Iterator[Webhook]:
@@ -7,6 +7,7 @@ from pydantic import Field
7
7
  from fiddler.constants.alert_rule import AlertCondition, BinSize, CompareTo, Priority
8
8
  from fiddler.schemas.base import BaseModel
9
9
  from fiddler.schemas.baseline import BaselineCompactResp
10
+ from fiddler.schemas.custom_expression import SegmentCompactResp
10
11
  from fiddler.schemas.model import ModelCompactResp
11
12
  from fiddler.schemas.project import ProjectCompactResp
12
13
 
@@ -17,14 +18,14 @@ class AlertRuleResp(BaseModel):
17
18
  model: ModelCompactResp
18
19
  project: ProjectCompactResp
19
20
  baseline: Optional[BaselineCompactResp]
21
+ segment: Optional[SegmentCompactResp]
20
22
  priority: Union[str, Priority]
21
23
  compare_to: Union[str, CompareTo]
22
24
  metric_id: Union[str, UUID]
23
25
  critical_threshold: float
24
26
  condition: Union[str, AlertCondition]
25
27
  bin_size: Union[str, BinSize]
26
- columns: Optional[List[str]]
27
- baseline_id: Optional[UUID]
28
+ columns: Optional[List[str]] = Field(alias='feature_names')
28
29
  compare_bin_delta: Optional[int]
29
30
  warning_threshold: Optional[float]
30
31
 
@@ -29,3 +29,10 @@ class CustomMetricResp(CustomExpressionResp):
29
29
 
30
30
  class SegmentResp(CustomExpressionResp):
31
31
  """Segment response object"""
32
+
33
+
34
+ class SegmentCompactResp(BaseModel):
35
+ """Segment compact response object"""
36
+
37
+ id: UUID
38
+ name: str
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, List, Optional, Type, TypeVar
1
+ from typing import Any, Dict, List, Optional, Type, TypeVar, Literal
2
2
 
3
3
  from pydantic import BaseModel, validator
4
4
 
@@ -10,18 +10,12 @@ CustomFeatureTypeVar = TypeVar('CustomFeatureTypeVar', bound='CustomFeature')
10
10
 
11
11
  class CustomFeature(BaseModel):
12
12
  name: str
13
- type: CustomFeatureType
14
- n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
15
- centroids: Optional[List] = None
16
-
17
- @validator('n_clusters')
18
- def validate_n_clusters(cls, value: int) -> int: # noqa: N805
19
- if value < 0:
20
- raise ValueError('n_clusters must be greater than 0')
21
- return value
13
+ type: Any
22
14
 
23
15
  class Config:
24
16
  allow_mutation = False
17
+ use_enum_values = True
18
+ discriminator = 'type'
25
19
 
26
20
  @classmethod
27
21
  def from_columns(
@@ -53,12 +47,13 @@ class CustomFeature(BaseModel):
53
47
  return_dict: Dict[str, Any] = {
54
48
  'name': self.name,
55
49
  'type': self.type.value,
56
- 'n_clusters': self.n_clusters,
57
50
  }
58
51
  if isinstance(self, Multivariate):
59
52
  return_dict['columns'] = self.columns
53
+ return_dict['n_clusters'] = self.n_clusters
60
54
  elif isinstance(self, VectorFeature):
61
55
  return_dict['column'] = self.column
56
+ return_dict['n_clusters'] = self.n_clusters
62
57
  if isinstance(self, (ImageEmbedding, TextEmbedding)):
63
58
  return_dict['source_column'] = self.source_column
64
59
  if isinstance(self, TextEmbedding):
@@ -74,7 +69,9 @@ class CustomFeature(BaseModel):
74
69
 
75
70
 
76
71
  class Multivariate(CustomFeature):
77
- type: CustomFeatureType = CustomFeatureType.FROM_COLUMNS
72
+ type: Literal['FROM_COLUMNS'] = CustomFeatureType.FROM_COLUMNS.value
73
+ n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
74
+ centroids: Optional[List] = None
78
75
  columns: List[str]
79
76
  monitor_components: bool = False
80
77
 
@@ -84,22 +81,31 @@ class Multivariate(CustomFeature):
84
81
  raise ValueError('Multivariate columns must be greater than 1')
85
82
  return value
86
83
 
84
+ @validator('n_clusters')
85
+ def validate_n_clusters(cls, value: int) -> int: # noqa: N805
86
+ if value < 0:
87
+ raise ValueError('n_clusters must be greater than 0')
88
+ return value
89
+
87
90
 
88
91
  class VectorFeature(CustomFeature):
89
- type: CustomFeatureType = CustomFeatureType.FROM_VECTOR
90
- source_column: Optional[str] = None
92
+ type: Literal['FROM_VECTOR'] = CustomFeatureType.FROM_VECTOR.value
93
+ n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
94
+ centroids: Optional[List] = None
91
95
  column: str
92
96
 
97
+ @validator('n_clusters')
98
+ def validate_n_clusters(cls, value: int) -> int: # noqa: N805
99
+ if value < 0:
100
+ raise ValueError('n_clusters must be greater than 0')
101
+ return value
102
+
93
103
 
94
104
  class TextEmbedding(VectorFeature):
95
- type: CustomFeatureType = CustomFeatureType.FROM_TEXT_EMBEDDING
105
+ type: Literal['FROM_TEXT_EMBEDDING'] = CustomFeatureType.FROM_TEXT_EMBEDDING.value # type: ignore
106
+ source_column: str
96
107
  n_tags: Optional[int] = DEFAULT_NUM_TAGS
97
-
98
- @validator('source_column')
99
- def validate_source_column(cls, value: str) -> str: # noqa: N805
100
- if value is None:
101
- raise ValueError('source_column must be specified')
102
- return value
108
+ tf_idf: Optional[Dict[str, List]] = None
103
109
 
104
110
  @validator('n_tags')
105
111
  def validate_n_tags(cls, value: int) -> int: # noqa: N805
@@ -109,13 +115,8 @@ class TextEmbedding(VectorFeature):
109
115
 
110
116
 
111
117
  class ImageEmbedding(VectorFeature):
112
- type: CustomFeatureType = CustomFeatureType.FROM_IMAGE_EMBEDDING
113
-
114
- @validator('source_column')
115
- def validate_source_column(cls, value: str) -> str: # noqa: N805
116
- if value is None:
117
- raise ValueError('source_column must be specified')
118
- return value
118
+ type: Literal['FROM_IMAGE_EMBEDDING'] = CustomFeatureType.FROM_IMAGE_EMBEDDING.value # type: ignore
119
+ source_column: str
119
120
 
120
121
 
121
122
  class Enrichment(CustomFeature):
@@ -134,7 +135,7 @@ class Enrichment(CustomFeature):
134
135
  """
135
136
 
136
137
  # Setting the feature type to ENRICHMENT
137
- type: CustomFeatureType = CustomFeatureType.ENRICHMENT
138
+ type: Literal['ENRICHMENT'] = CustomFeatureType.ENRICHMENT.value
138
139
 
139
140
  # List of input column names used to generate the enrichment
140
141
  columns: List[str]
@@ -17,6 +17,7 @@ from fiddler.schemas.xai_params import XaiParams
17
17
  class ModelCompactResp(BaseModel):
18
18
  id: UUID
19
19
  name: str
20
+ version: Optional[str]
20
21
 
21
22
 
22
23
  class ModelResp(BaseModel):
@@ -0,0 +1,32 @@
1
+ from typing import List, Union
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from fiddler.schemas.custom_features import Multivariate, VectorFeature, TextEmbedding, ImageEmbedding, Enrichment
6
+
7
+
8
+ class ModelSpec(BaseModel):
9
+ """Model spec defines how model columns are used along with model task"""
10
+
11
+ schema_version: int = 1
12
+ """Schema version"""
13
+
14
+ inputs: List[str] = Field(default_factory=list)
15
+ """Feature columns"""
16
+
17
+ outputs: List[str] = Field(default_factory=list)
18
+ """Prediction columns"""
19
+
20
+ targets: List[str] = Field(default_factory=list)
21
+ """Label columns"""
22
+
23
+ decisions: List[str] = Field(default_factory=list)
24
+ """Decisions columns"""
25
+
26
+ metadata: List[str] = Field(default_factory=list)
27
+ """Metadata columns"""
28
+
29
+ custom_features: List[Union[Multivariate, VectorFeature, TextEmbedding, ImageEmbedding, Enrichment]] = Field(
30
+ default_factory=list
31
+ )
32
+ """Custom feature definitions"""
@@ -28,54 +28,61 @@ from fiddler.utils.logger import set_logging
28
28
 
29
29
  API_RESPONSE_200 = {
30
30
  'data': {
31
- 'feature_names': ['age'],
32
- 'id': 620,
33
- 'created_at': '2023-11-28T08:04:12.651937+00:00',
31
+ 'id': 794,
34
32
  'organization_name': 'mainbuild',
35
- 'compare_period': None,
36
- 'time_bucket': 3600000,
37
- 'alert_type': 'data_integrity',
38
- 'metric_display_name': 'Missing Value Violation',
39
- 'enable_notification': True,
40
- 'last_updated': '2023-11-28T08:04:12.653346+00:00',
41
- 'alert_type_display_name': 'Data Integrity',
42
- 'critical_threshold': 0.0,
33
+ 'project_name': PROJECT_NAME,
34
+ 'model_id': 285,
35
+ 'name': 'test_rule',
36
+ 'metric': 'jsd',
37
+ 'metric_id': 'jsd',
38
+ 'metric_display_name': 'Jensen-Shannon Distance',
39
+ 'alert_type': 'drift',
40
+ 'alert_type_display_name': 'Data Drift',
41
+ 'priority': 'MEDIUM',
43
42
  'baseline_name': BASELINE_NAME,
44
- 'baseline': {
45
- 'id': BASELINE_ID,
46
- 'name': BASELINE_NAME,
47
- },
43
+ 'feature_names': ['creditscore'],
44
+ 'time_bucket': 3600000,
45
+ 'category': None,
46
+ 'bin_size': 'Hour',
47
+ 'compare_to': 'raw_value',
48
48
  'condition': 'greater',
49
- 'uuid': ALERT_RULE_ID,
50
- 'segment': None,
51
- 'warning_threshold': None,
52
- 'name': 'Age Missing 1 Hr',
53
- 'model_name': MODEL_NAME,
54
- 'model': {
55
- 'id': MODEL_ID,
56
- 'name': MODEL_NAME,
57
- },
49
+ 'compare_period': None,
50
+ 'warning_threshold': 1.0,
51
+ 'critical_threshold': 2.3,
58
52
  'is_active': True,
59
53
  'created_by': 'admin@fiddler.ai',
60
- 'bin_size': 'Hour',
61
- 'category': None,
62
- 'project_name': PROJECT_NAME,
63
- 'project': {
64
- 'id': PROJECT_ID,
65
- 'name': PROJECT_NAME,
54
+ 'created_at': '2024-04-23T10:34:14.321895+00:00',
55
+ 'last_updated': '2024-04-23T10:34:14.323554+00:00',
56
+ 'model_name': 'bank_churn',
57
+ 'enable_notification': True,
58
+ 'segment': {
59
+ 'id': '1c9b551a-808b-4ef0-b67b-e788eaf1e6de',
60
+ 'organization_name': 'mainbuild',
61
+ 'project_name': 'nick_test_project_11',
62
+ 'model_name': 'bank_churn',
63
+ 'name': 'xyzab',
64
+ 'definition': 'Age > 10',
65
+ 'description': 'meh',
66
+ 'created_at': '2024-04-23T10:31:52.181550+00:00',
67
+ 'created_by': {
68
+ 'id': 1,
69
+ 'full_name': 'Fiddler Administrator',
70
+ 'email': 'admin@fiddler.ai',
71
+ },
66
72
  },
67
- 'metric': 'null_violation_count',
68
- 'metric_id': 'null_violation_count',
69
- 'compare_to': 'raw_value',
70
- 'priority': 'HIGH',
73
+ 'project': {'id': PROJECT_ID, 'name': PROJECT_NAME},
74
+ 'model': {'id': MODEL_ID, 'name': MODEL_NAME, 'version': 'v1'},
75
+ 'baseline': {'id': BASELINE_ID, 'name': BASELINE_NAME},
76
+ 'compare_bin_delta': None,
77
+ 'uuid': ALERT_RULE_ID,
71
78
  'notifications': {
72
- 'emails': {'alert_config_uuid': ALERT_RULE_ID, 'email': 'admin@fiddler.ai'},
73
79
  'pagerduty': {
74
- 'severity': '',
75
80
  'alert_config_uuid': ALERT_RULE_ID,
76
81
  'service': '',
82
+ 'severity': '',
77
83
  },
78
- 'webhooks': [{'uuid': 'e20bf4cc-d2cf-4540-baef-d96913b14f1b'}],
84
+ 'emails': {'email': ''},
85
+ 'webhooks': [],
79
86
  },
80
87
  },
81
88
  'api_version': '2.0',
@@ -20,6 +20,7 @@ from fiddler.tests.constants import (
20
20
  DATASET_NAME,
21
21
  MODEL_ID,
22
22
  MODEL_NAME,
23
+ MODEL_VERSION,
23
24
  PROJECT_ID,
24
25
  PROJECT_NAME,
25
26
  USER_EMAIL,
@@ -39,7 +40,9 @@ class DummyEntity(
39
40
  def __init__(self) -> None:
40
41
  self._resp = mock.MagicMock()
41
42
  self._resp.project = ProjectCompactResp(id=PROJECT_ID, name=PROJECT_NAME)
42
- self._resp.model = ModelCompactResp(id=MODEL_ID, name=MODEL_NAME)
43
+ self._resp.model = ModelCompactResp(
44
+ id=MODEL_ID, name=MODEL_NAME, version=MODEL_VERSION
45
+ )
43
46
  self._resp.dataset = DatasetCompactResp(
44
47
  id=DATASET_ID, name=DATASET_NAME, type=EnvType.PRE_PRODUCTION
45
48
  )