fiddler-client 3.6.0__tar.gz → 3.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fiddler_client-3.6.0/fiddler_client.egg-info → fiddler_client-3.7.0}/PKG-INFO +3 -3
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/PUBLIC.md +2 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/README.md +76 -3
- fiddler_client-3.7.0/fiddler/VERSION +1 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/__init__.py +1 -1
- fiddler_client-3.7.0/fiddler/configs.py +13 -0
- fiddler_client-3.7.0/fiddler/connection.py +262 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/common.py +0 -2
- fiddler_client-3.7.0/fiddler/decorators.py +85 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/alert_rule.py +8 -5
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/baseline.py +4 -3
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/custom_expression.py +1 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/events.py +19 -4
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/file.py +15 -8
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/job.py +9 -9
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/model.py +31 -4
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/model_artifact.py +3 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/model_deployment.py +6 -6
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/project.py +19 -1
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/surrogate.py +9 -3
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/webhook.py +6 -1
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/xai.py +19 -7
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/exceptions.py +4 -2
- fiddler_client-3.7.0/fiddler/libs/aws.py +95 -0
- fiddler_client-3.7.0/fiddler/libs/http_client.py +587 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/libs/semver.py +2 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/packtools/project_attributions_helpers.py +10 -8
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/custom_features.py +1 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/model_spec.py +18 -3
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_alert_record.py +2 -1
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_alert_rule.py +3 -18
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_baseline.py +3 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_dataset.py +3 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_events.py +64 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_files.py +11 -1
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_generate_model.py +3 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_model.py +40 -3
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_project.py +58 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_webhook.py +2 -1
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/test_connection.py +0 -2
- fiddler_client-3.7.0/fiddler/tests/test_logger.py +61 -0
- fiddler_client-3.7.0/fiddler/tests/test_sagemaker_auth.py +73 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/utils/decorators.py +2 -2
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/utils/helpers.py +2 -2
- fiddler_client-3.7.0/fiddler/utils/logger.py +76 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/utils/model_generator.py +1 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0/fiddler_client.egg-info}/PKG-INFO +3 -3
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler_client.egg-info/SOURCES.txt +2 -0
- fiddler_client-3.6.0/fiddler/VERSION +0 -1
- fiddler_client-3.6.0/fiddler/configs.py +0 -8
- fiddler_client-3.6.0/fiddler/connection.py +0 -191
- fiddler_client-3.6.0/fiddler/decorators.py +0 -52
- fiddler_client-3.6.0/fiddler/libs/http_client.py +0 -221
- fiddler_client-3.6.0/fiddler/tests/test_logger.py +0 -12
- fiddler_client-3.6.0/fiddler/utils/logger.py +0 -23
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/LICENSE.txt +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/MANIFEST.in +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/alert_rule.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/baseline.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/dataset.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/events.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/job.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/model.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/model_deployment.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/constants/xai.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/alert_record.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/base.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/dataset.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/organization.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/entities/user.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/libs/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/libs/json_encoder.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/packtools/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/packtools/gem.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/packtools/keras_ig_helpers.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/packtools/template_model.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/alert_record.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/alert_rule.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/base.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/baseline.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/custom_expression.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/dataset.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/events.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/file.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/filter_query.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/job.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/model.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/model_deployment.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/model_schema.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/model_task_params.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/organization.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/project.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/response.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/server_info.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/user.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/webhook.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/xai.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/schemas/xai_params.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_custom_metric.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_job.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_mixin.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_model_artifact.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_model_deployment.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_model_surrogate.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_segment.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/apis/test_xai.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/conftest.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/constants.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/test_json_encoder.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/test_utils.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/tests/utils.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/utils/__init__.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/utils/validations.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/utils/version.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler/version.py +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler_client.egg-info/dependency_links.txt +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler_client.egg-info/requires.txt +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/fiddler_client.egg-info/top_level.txt +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/setup.cfg +0 -0
- {fiddler_client-3.6.0 → fiddler_client-3.7.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fiddler-client
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.0
|
|
4
4
|
Summary: Python client for Fiddler Platform
|
|
5
5
|
Home-page: https://fiddler.ai
|
|
6
6
|
Author: Fiddler Labs
|
|
@@ -30,7 +30,7 @@ publishing for use with our monitoring features.
|
|
|
30
30
|
|
|
31
31
|
Requirements
|
|
32
32
|
------------
|
|
33
|
-
Requires Python >= Python-3.
|
|
33
|
+
Requires Python >= Python-3.9 and pip >= 19.0
|
|
34
34
|
|
|
35
35
|
Installation
|
|
36
36
|
------------
|
|
@@ -39,7 +39,7 @@ Installation
|
|
|
39
39
|
|
|
40
40
|
API Example Usage
|
|
41
41
|
-------------
|
|
42
|
-
Documentation for the API can be found [here](https://docs.fiddler.ai
|
|
42
|
+
Documentation for the API can be found [here](https://docs.fiddler.ai). 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
43
|
|
|
44
44
|
Version History
|
|
45
45
|
-------------
|
|
@@ -6,7 +6,7 @@ publishing for use with our monitoring features.
|
|
|
6
6
|
|
|
7
7
|
Requirements
|
|
8
8
|
------------
|
|
9
|
-
Requires Python >= Python-3.
|
|
9
|
+
Requires Python >= Python-3.9 and pip >= 19.0
|
|
10
10
|
|
|
11
11
|
Installation
|
|
12
12
|
------------
|
|
@@ -15,7 +15,7 @@ Installation
|
|
|
15
15
|
|
|
16
16
|
API Example Usage
|
|
17
17
|
-------------
|
|
18
|
-
Documentation for the API can be found [here](https://docs.fiddler.ai
|
|
18
|
+
Documentation for the API can be found [here](https://docs.fiddler.ai). 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
19
|
|
|
20
20
|
Version History
|
|
21
21
|
-------------
|
|
@@ -2,7 +2,80 @@
|
|
|
2
2
|
|
|
3
3
|
A Python library for interacting with the Fiddler HTTP API.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Development
|
|
6
|
+
|
|
7
|
+
Run unit tests:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
$ make test
|
|
11
|
+
...
|
|
12
|
+
156 passed, 1 skipped in 0.59s
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
Run mypy, pylint, ruff, flake8:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
$ make lint
|
|
20
|
+
mypy fiddler
|
|
21
|
+
Success: no issues found in 77 source files
|
|
22
|
+
ruff check .
|
|
23
|
+
All checks passed!
|
|
24
|
+
pylint fiddler
|
|
25
|
+
...
|
|
26
|
+
flake8 fiddler
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Logging
|
|
31
|
+
|
|
32
|
+
### Automatic log handler setup for ad-hoc scripts
|
|
33
|
+
|
|
34
|
+
Consider this minimal Python program:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import fiddler
|
|
38
|
+
|
|
39
|
+
# The call to `init()` below detects that there is no root logger configured.
|
|
40
|
+
# It automatically configures an outlet for log messages generated by this
|
|
41
|
+
# library: they end up being written to stderr with a meaningful default log
|
|
42
|
+
# format.
|
|
43
|
+
fiddler.init(url="https://f.bar", token="x")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This feature can be disabled by passing `auto_attach_log_handler=False` to `init()`.
|
|
47
|
+
|
|
48
|
+
### Full control in calling code: configure a root logger
|
|
49
|
+
|
|
50
|
+
Any more complex Python program that uses this client library typically sets up the logging machinery in a custom way. Example:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import logging
|
|
54
|
+
import os
|
|
55
|
+
|
|
56
|
+
import fiddler
|
|
57
|
+
|
|
58
|
+
# Example for configuring a root logger, with a stream handler attached for
|
|
59
|
+
# emission to stderr:
|
|
60
|
+
logging.basicConfig(
|
|
61
|
+
level=logging.INFO,
|
|
62
|
+
format="%(asctime)s.%(msecs)03d %(levelname)s: %(message)s",
|
|
63
|
+
datefmt="%y%m%d-%H:%M:%S",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Now, the call to init() below does not attach any additional log handlers.
|
|
67
|
+
# Log messages emitted by this client library are simply propagated into the
|
|
68
|
+
# root logger (and adhere to custom filtering and formatting rules).
|
|
69
|
+
fiddler.init(url="https://f.bar", token="x")
|
|
70
|
+
|
|
71
|
+
# Example for custom verbosity control: do not forward DEBUG+INFO level
|
|
72
|
+
# messages from the 'fiddler' logger into the root logger.
|
|
73
|
+
logging.getLogger('fiddler').setLevel(logging.WARNING)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Releasing
|
|
77
|
+
|
|
78
|
+
### Pre Release
|
|
6
79
|
|
|
7
80
|
As we get ready for distribution of the updated python client we need to ensure that all the associated downstream artifacts are updated.
|
|
8
81
|
|
|
@@ -16,7 +89,7 @@ As we get ready for distribution of the updated python client we need to ensure
|
|
|
16
89
|
- If it's a new feature appropriate care has to be taken to
|
|
17
90
|
- Customer Success needs to sign off on the changes and they need to plan for customer update
|
|
18
91
|
|
|
19
|
-
|
|
92
|
+
### PyPI
|
|
20
93
|
|
|
21
94
|
The Fiddler Python client is published as
|
|
22
95
|
[`fiddler-client`](https://pypi.org/project/fiddler-client/) in the Python
|
|
@@ -42,7 +115,7 @@ Note: dev versions may be published from any branch at any time by using a
|
|
|
42
115
|
`.devN` affix, as described in [PEP-440](https://peps.python.org/pep-0440/). For
|
|
43
116
|
example: `1.4.3.dev5`.
|
|
44
117
|
|
|
45
|
-
|
|
118
|
+
### Post Release
|
|
46
119
|
|
|
47
120
|
1. Inform on `#releases` slack channel of the python client release with release notes.
|
|
48
121
|
1. Verify:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.7.0
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
MIN_SERVER_VERSION = '24.4.0'
|
|
2
|
+
DEFAULT_PAGE_SIZE = 50
|
|
3
|
+
|
|
4
|
+
# In seconds. For example, this generates a log message every N seconds. Was
|
|
5
|
+
# once set to 3, and I think that was too frequent. If this needs to be
|
|
6
|
+
# snappier and apply to both, short-running jobs as well as long-running jobs:
|
|
7
|
+
# we can grow the interval between polls.
|
|
8
|
+
JOB_POLL_INTERVAL = 6
|
|
9
|
+
JOB_WAIT_TIMEOUT = 1800
|
|
10
|
+
|
|
11
|
+
STREAM_EVENT_LIMIT = 1000
|
|
12
|
+
DEFAULT_NUM_CLUSTERS = 5
|
|
13
|
+
DEFAULT_NUM_TAGS = 5
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from functools import cached_property
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
import fiddler.utils.logger
|
|
8
|
+
from fiddler.configs import MIN_SERVER_VERSION
|
|
9
|
+
from fiddler.constants.common import (
|
|
10
|
+
CLIENT_NAME,
|
|
11
|
+
FIDDLER_CLIENT_NAME_HEADER,
|
|
12
|
+
FIDDLER_CLIENT_VERSION_HEADER,
|
|
13
|
+
)
|
|
14
|
+
from fiddler.decorators import handle_api_error
|
|
15
|
+
from fiddler.exceptions import IncompatibleClient
|
|
16
|
+
from fiddler.libs.http_client import RequestClient
|
|
17
|
+
from fiddler.schemas.server_info import ServerInfo, Version
|
|
18
|
+
from fiddler.utils.version import match_semver
|
|
19
|
+
from fiddler.version import __version__
|
|
20
|
+
|
|
21
|
+
log = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Connection:
|
|
25
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
26
|
+
self,
|
|
27
|
+
url: str,
|
|
28
|
+
token: str,
|
|
29
|
+
proxies: dict | None = None,
|
|
30
|
+
timeout: float | tuple[float, float] | None = None,
|
|
31
|
+
verify: bool = True,
|
|
32
|
+
validate: bool = True,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Initiate connection.
|
|
36
|
+
|
|
37
|
+
:param url:
|
|
38
|
+
The base URL to your Fiddler platform.
|
|
39
|
+
:param token:
|
|
40
|
+
An authentication token, obtained via the Fiddler UI.
|
|
41
|
+
:param proxies:
|
|
42
|
+
A dictionary mapping protocol to the URL of the proxy.
|
|
43
|
+
:param timeout:
|
|
44
|
+
Allows for overriding default HTTP request timeout settings.
|
|
45
|
+
Applies to all HTTP requests emitted with this connection object.
|
|
46
|
+
Can be a float or two floats, also see
|
|
47
|
+
https://requests.readthedocs.io/en/latest/user/advanced/#timeouts
|
|
48
|
+
:param verify:
|
|
49
|
+
Can be used to disable server's TLS certificate verification.
|
|
50
|
+
Certificate verification is enabled by default.
|
|
51
|
+
:param validate:
|
|
52
|
+
Whether to validate the server/client version compatibility. Some
|
|
53
|
+
features might not work as expected if this is turned off.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
self.url = url
|
|
57
|
+
self.token = token
|
|
58
|
+
self.proxies = proxies
|
|
59
|
+
self.timeout = timeout
|
|
60
|
+
self.verify = verify
|
|
61
|
+
|
|
62
|
+
if not url:
|
|
63
|
+
raise ValueError('`url` is empty')
|
|
64
|
+
|
|
65
|
+
if not token:
|
|
66
|
+
raise ValueError('`token` is empty')
|
|
67
|
+
|
|
68
|
+
self.request_headers = {
|
|
69
|
+
'Authorization': f'Bearer {token}',
|
|
70
|
+
FIDDLER_CLIENT_NAME_HEADER: CLIENT_NAME,
|
|
71
|
+
FIDDLER_CLIENT_VERSION_HEADER: __version__,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if validate:
|
|
75
|
+
self._check_server_version()
|
|
76
|
+
self._check_version_compatibility()
|
|
77
|
+
|
|
78
|
+
@cached_property
|
|
79
|
+
def client(self) -> RequestClient:
|
|
80
|
+
"""Request client instance"""
|
|
81
|
+
return RequestClient(
|
|
82
|
+
base_url=self.url,
|
|
83
|
+
headers=self.request_headers,
|
|
84
|
+
proxies=self.proxies,
|
|
85
|
+
verify=self.verify,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@cached_property
|
|
89
|
+
def server_info(self) -> ServerInfo:
|
|
90
|
+
"""Server info instance"""
|
|
91
|
+
return self._get_server_info()
|
|
92
|
+
|
|
93
|
+
@cached_property
|
|
94
|
+
def server_version(self) -> Version:
|
|
95
|
+
"""Server semver version"""
|
|
96
|
+
return self.server_info.server_version
|
|
97
|
+
|
|
98
|
+
@cached_property
|
|
99
|
+
def organization_name(self) -> str:
|
|
100
|
+
"""Organization name"""
|
|
101
|
+
return self.server_info.organization.name
|
|
102
|
+
|
|
103
|
+
@cached_property
|
|
104
|
+
def organization_id(self) -> UUID:
|
|
105
|
+
"""Organization id"""
|
|
106
|
+
return self.server_info.organization.id
|
|
107
|
+
|
|
108
|
+
@handle_api_error
|
|
109
|
+
def _get_server_info(self) -> ServerInfo:
|
|
110
|
+
"""Get server info"""
|
|
111
|
+
|
|
112
|
+
# Tight-ish timeout.
|
|
113
|
+
response = self.client.get(url='/v3/server-info', timeout=(5, 15))
|
|
114
|
+
|
|
115
|
+
return ServerInfo(**response.json().get('data'))
|
|
116
|
+
|
|
117
|
+
@handle_api_error
|
|
118
|
+
def _check_version_compatibility(self) -> None:
|
|
119
|
+
"""Check whether Client version is compatible with Fiddler Platform version"""
|
|
120
|
+
|
|
121
|
+
self.client.get(
|
|
122
|
+
url='/v3/version-compatibility',
|
|
123
|
+
params={
|
|
124
|
+
'client_version': __version__,
|
|
125
|
+
'client_name': CLIENT_NAME,
|
|
126
|
+
},
|
|
127
|
+
timeout=(5, 15),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def _check_server_version(self) -> None:
|
|
131
|
+
"""Check whether Fiddler Platform version is compatible with Client version"""
|
|
132
|
+
if match_semver(self.server_version, f'>={MIN_SERVER_VERSION}'):
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
raise IncompatibleClient(server_version=str(self.server_version))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class ConnectionMixin:
|
|
139
|
+
@classmethod
|
|
140
|
+
def _conn(cls) -> Connection:
|
|
141
|
+
"""Fiddler connection instance"""
|
|
142
|
+
from fiddler import conn # pylint: disable=import-outside-toplevel
|
|
143
|
+
|
|
144
|
+
assert conn is not None
|
|
145
|
+
return conn
|
|
146
|
+
|
|
147
|
+
@classmethod
|
|
148
|
+
def _client(cls) -> RequestClient:
|
|
149
|
+
"""Request client instance"""
|
|
150
|
+
return cls._conn().client
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def organization_name(self) -> str:
|
|
154
|
+
"""Organization name property"""
|
|
155
|
+
return self._conn().server_info.organization.name
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def organization_id(self) -> UUID:
|
|
159
|
+
"""Organization id property"""
|
|
160
|
+
return self._conn().server_info.organization.id
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def get_organization_name(cls) -> str:
|
|
164
|
+
"""Organization name"""
|
|
165
|
+
return cls._conn().server_info.organization.name
|
|
166
|
+
|
|
167
|
+
@classmethod
|
|
168
|
+
def get_organization_id(cls) -> UUID:
|
|
169
|
+
"""Organization id"""
|
|
170
|
+
return cls._conn().server_info.organization.id
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def init( # pylint: disable=too-many-arguments
|
|
174
|
+
url: str,
|
|
175
|
+
token: str,
|
|
176
|
+
proxies: dict | None = None,
|
|
177
|
+
timeout: float | tuple[float, float] | None = None,
|
|
178
|
+
verify: bool = True,
|
|
179
|
+
validate: bool = True,
|
|
180
|
+
auto_attach_log_handler: bool = True,
|
|
181
|
+
) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Initialize the client.
|
|
184
|
+
|
|
185
|
+
:param url:
|
|
186
|
+
The base URL to your Fiddler platform.
|
|
187
|
+
:param token:
|
|
188
|
+
An authentication token, obtained via the Fiddler UI (can be found on
|
|
189
|
+
the Credentials tab of the Settings page).
|
|
190
|
+
:param proxies:
|
|
191
|
+
A dictionary mapping protocol to the URL of the proxy.
|
|
192
|
+
:param timeout:
|
|
193
|
+
Allows for overriding default HTTP request timeout settings. Applies to
|
|
194
|
+
all HTTP requests emitted by this client. Can be a float or two floats,
|
|
195
|
+
also see
|
|
196
|
+
https://requests.readthedocs.io/en/latest/user/advanced/#timeouts. This
|
|
197
|
+
client library tries to implement meaningful default timeout settings.
|
|
198
|
+
If you find yourself having to set this parameter to address a problem
|
|
199
|
+
please also contact the Fiddler customer support.
|
|
200
|
+
:param verify:
|
|
201
|
+
Can be used to disable server's TLS certificate verification.
|
|
202
|
+
Certificate verification is enabled by default.
|
|
203
|
+
:param validate:
|
|
204
|
+
Whether to validate the server/client version compatibility. Some
|
|
205
|
+
features might not work as expected if this is turned off.
|
|
206
|
+
:param auto_attach_log_handler:
|
|
207
|
+
Defaults to `True`. Can be used to disable the mechanism by which this
|
|
208
|
+
library may attach a stream handler for emitting log messages to stderr
|
|
209
|
+
(see below for further details).
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
The Fiddler client library will see HTTP API calls fail due to for example
|
|
213
|
+
transient networking issues, temporary backend problems, or as of rate
|
|
214
|
+
limiting errors. These kinds of failures are retryable. It is a sensible
|
|
215
|
+
choice to retry any affected API call after a short waiting period.
|
|
216
|
+
Therefore, this client library implements an automatic retry strategy. Most
|
|
217
|
+
HTTP requests are retried for up to certain amount of time.
|
|
218
|
+
|
|
219
|
+
You can take control of this maximum retry duration by setting the
|
|
220
|
+
environment variable `FIDDLER_CLIENT_RETRY_MAX_DURATION_SECONDS` to a
|
|
221
|
+
numeric value. It currently defaults to 300 seconds which allows for
|
|
222
|
+
auto-healing smaller outages.
|
|
223
|
+
|
|
224
|
+
Note that this client library logs HTTP interaction (and retrying details)
|
|
225
|
+
on INFO level via Python's standard library logging module under the
|
|
226
|
+
'fiddler' namespace.
|
|
227
|
+
|
|
228
|
+
If you do not configure a root logger in your Python interpreter context
|
|
229
|
+
(done via e.g. `logging.basicConfig()`) then this library automatically
|
|
230
|
+
attaches a handler for its log messages to be emitted on `stderr`. This
|
|
231
|
+
behavior can be disabled by setting `auto_attach_log_handler=False`. For
|
|
232
|
+
fine-grained control, consider configuring handlers and formatters
|
|
233
|
+
yourself.
|
|
234
|
+
|
|
235
|
+
The Fiddler client library has AWS SageMaker partner application
|
|
236
|
+
authentication support. To enable that, install the SageMaker Python SDK
|
|
237
|
+
(`sagemaker` on PyPI). Then, before calling `fiddler.init()` set the
|
|
238
|
+
environment variable AWS_PARTNER_APP_AUTH to 'true' and also set
|
|
239
|
+
AWS_PARTNER_APP_ARN/AWS_PARTNER_APP_URL to meaningful values.
|
|
240
|
+
"""
|
|
241
|
+
from fiddler import _set_conn # pylint: disable=import-outside-toplevel
|
|
242
|
+
|
|
243
|
+
# If this library is imported into an interpreter that has a root logger
|
|
244
|
+
# configured (with handler(s) attached) then just propagate log messages
|
|
245
|
+
# into that hierarchy, and do not attach a handler to the 'fiddler' logger.
|
|
246
|
+
if not logging.getLogger().handlers and auto_attach_log_handler:
|
|
247
|
+
fiddler.utils.logger._attach_handler()
|
|
248
|
+
log.info(
|
|
249
|
+
'attached stderr handler to logger: auto_attach_log_handler=True, and root logger not configured'
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Singleton object in Python interpreter.
|
|
253
|
+
conn = Connection(
|
|
254
|
+
url=url,
|
|
255
|
+
token=token,
|
|
256
|
+
proxies=proxies,
|
|
257
|
+
timeout=timeout,
|
|
258
|
+
verify=verify,
|
|
259
|
+
validate=validate,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
_set_conn(conn_=conn)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Callable, TypeVar, cast
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
import pydantic.v1
|
|
8
|
+
|
|
9
|
+
from fiddler.exceptions import ApiError, Conflict, HttpError, NotFound, Unsupported
|
|
10
|
+
from fiddler.schemas.response import ErrorResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
_WrappedFuncType = TypeVar( # pylint: disable=invalid-name
|
|
16
|
+
'_WrappedFuncType', bound=Callable[..., Any]
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ignore: fiddler/decorators.py:19:1: C901 'handle_api_error' is too complex (11)
|
|
21
|
+
def handle_api_error(func: _WrappedFuncType) -> _WrappedFuncType: # noqa: C901
|
|
22
|
+
@wraps(func)
|
|
23
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
24
|
+
try:
|
|
25
|
+
return func(*args, **kwargs)
|
|
26
|
+
except requests.JSONDecodeError as e:
|
|
27
|
+
# This often is premature use of `json()`. Calling code should
|
|
28
|
+
# first check the response for the expected status code, and only
|
|
29
|
+
# then attempt JSON-deserialization.
|
|
30
|
+
raise HttpError(message=f'Invalid JSON response - {e.doc}') # type: ignore
|
|
31
|
+
except requests.HTTPError as http_exc:
|
|
32
|
+
# Note(JP): when we're here it means we got an HTTP response.
|
|
33
|
+
# That's how this exception is documented.
|
|
34
|
+
|
|
35
|
+
status = http_exc.response.status_code
|
|
36
|
+
# The logging levels 'critical' and 'error' are generally meant to
|
|
37
|
+
# be used for terminal / fatal errors. Here, we handle many
|
|
38
|
+
# transient (retryable) errors, and it's fair to log them not as
|
|
39
|
+
# serious as actual errors. Therefore level WARNING and not ERROR.
|
|
40
|
+
# Even INFO might make sense.
|
|
41
|
+
logger.warning(
|
|
42
|
+
'%s HTTP request to %s failed with %s - %s',
|
|
43
|
+
http_exc.request.method,
|
|
44
|
+
getattr(http_exc.request, 'url', 'unknown'),
|
|
45
|
+
status,
|
|
46
|
+
# Not entire response body in case we have a megabyte response.
|
|
47
|
+
getattr(http_exc.response, 'content', 'missing')[:200],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Now, map the error at hand to an exception to be thrown towards
|
|
51
|
+
# the caller.
|
|
52
|
+
|
|
53
|
+
if status == HTTPStatus.METHOD_NOT_ALLOWED:
|
|
54
|
+
raise Unsupported()
|
|
55
|
+
|
|
56
|
+
# Did we get structured error information? This might even
|
|
57
|
+
# be wrapped in a 501 response for example.
|
|
58
|
+
try:
|
|
59
|
+
# https://github.com/fiddler-labs/fiddler/issues/9314
|
|
60
|
+
error_resp = ErrorResponse(**http_exc.response.json())
|
|
61
|
+
except pydantic.v1.ValidationError:
|
|
62
|
+
# We couldn't turn the HTTP error response into an object
|
|
63
|
+
# satisfying model='ErrorResponse'. Now, instead of exposing
|
|
64
|
+
# this to users as a pydantic.ValidationError (which is kinda
|
|
65
|
+
# useless to them) -- just re-raise requests.HTTPError, with
|
|
66
|
+
# all its useful error detail -- it is likely to show the
|
|
67
|
+
# actual problem.
|
|
68
|
+
raise http_exc
|
|
69
|
+
except requests.JSONDecodeError:
|
|
70
|
+
# Re-raise requests.HTTPError, with all its useful error
|
|
71
|
+
# detail.
|
|
72
|
+
raise http_exc
|
|
73
|
+
|
|
74
|
+
# This code path is only reachable if we could successfully
|
|
75
|
+
# deserialize an ErrorResponse object from the HTTP response body.
|
|
76
|
+
|
|
77
|
+
if status == HTTPStatus.CONFLICT:
|
|
78
|
+
raise Conflict(error_resp.error)
|
|
79
|
+
|
|
80
|
+
if status == HTTPStatus.NOT_FOUND:
|
|
81
|
+
raise NotFound(error_resp.error)
|
|
82
|
+
|
|
83
|
+
raise ApiError(error_resp.error)
|
|
84
|
+
|
|
85
|
+
return cast(_WrappedFuncType, wrapper)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import builtins
|
|
4
|
+
import logging
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
from typing import Any, Iterator
|
|
6
7
|
from uuid import UUID
|
|
@@ -15,9 +16,9 @@ from fiddler.entities.model import ModelCompactMixin
|
|
|
15
16
|
from fiddler.entities.project import ProjectCompactMixin
|
|
16
17
|
from fiddler.schemas.alert_rule import AlertRuleResp, NotificationConfig
|
|
17
18
|
from fiddler.schemas.filter_query import OperatorType, QueryCondition, QueryRule
|
|
18
|
-
from fiddler.utils.logger import get_logger
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class AlertRule(
|
|
@@ -235,6 +236,7 @@ class AlertRule(
|
|
|
235
236
|
response = self._client().post(
|
|
236
237
|
url=self._get_url(),
|
|
237
238
|
data=payload,
|
|
239
|
+
headers={'Content-Type': 'application/json'},
|
|
238
240
|
)
|
|
239
241
|
|
|
240
242
|
self._refresh_from_response(response=response)
|
|
@@ -244,17 +246,17 @@ class AlertRule(
|
|
|
244
246
|
def enable_notifications(self) -> None:
|
|
245
247
|
"""Enable notifications for an alert rule"""
|
|
246
248
|
self._client().patch(
|
|
247
|
-
url=self._get_url(id_=self.id),
|
|
249
|
+
url=self._get_url(id_=self.id), json={'enable_notification': True}
|
|
248
250
|
)
|
|
249
251
|
logger.info(
|
|
250
|
-
'
|
|
252
|
+
'notifications have been enabled for alert rule with id: %s', self.id
|
|
251
253
|
)
|
|
252
254
|
|
|
253
255
|
@handle_api_error
|
|
254
256
|
def disable_notifications(self) -> None:
|
|
255
257
|
"""Disable notifications for an alert rule"""
|
|
256
258
|
self._client().patch(
|
|
257
|
-
url=self._get_url(id_=self.id),
|
|
259
|
+
url=self._get_url(id_=self.id), json={'enable_notification': False}
|
|
258
260
|
)
|
|
259
261
|
logger.info(
|
|
260
262
|
'Notifications have been disabled for alert rule with id: %s', self.id
|
|
@@ -293,6 +295,7 @@ class AlertRule(
|
|
|
293
295
|
response = self._client().patch(
|
|
294
296
|
url=self._get_notification_url(id_=self.id),
|
|
295
297
|
data=payload,
|
|
298
|
+
headers={'Content-Type': 'application/json'},
|
|
296
299
|
)
|
|
297
300
|
|
|
298
301
|
return NotificationConfig(**response.json()['data'])
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# pylint: disable=E1101
|
|
2
|
+
# E1101: Instance of 'FieldInfo' has no 'type' member (no-member)
|
|
1
3
|
from __future__ import annotations
|
|
2
4
|
|
|
3
5
|
from dataclasses import dataclass
|
|
@@ -17,9 +19,7 @@ from fiddler.schemas.filter_query import OperatorType, QueryCondition, QueryRule
|
|
|
17
19
|
from fiddler.utils.helpers import raise_not_found
|
|
18
20
|
|
|
19
21
|
|
|
20
|
-
class Baseline(
|
|
21
|
-
BaseEntity, ModelCompactMixin, ProjectCompactMixin, DatasetCompactMixin
|
|
22
|
-
): # pylint: disable=too-many-instance-attributes
|
|
22
|
+
class Baseline(BaseEntity, ModelCompactMixin, ProjectCompactMixin, DatasetCompactMixin): # pylint: disable=too-many-instance-attributes
|
|
23
23
|
def __init__( # pylint: disable=too-many-arguments
|
|
24
24
|
self,
|
|
25
25
|
name: str,
|
|
@@ -219,6 +219,7 @@ class Baseline(
|
|
|
219
219
|
response = self._client().post(
|
|
220
220
|
url=self._get_url(),
|
|
221
221
|
data=payload,
|
|
222
|
+
headers={'Content-Type': 'application/json'},
|
|
222
223
|
)
|
|
223
224
|
self._refresh_from_response(response=response)
|
|
224
225
|
return self
|
|
@@ -173,6 +173,7 @@ class CustomExpression(BaseEntity, ModelCompactMixin, ProjectCompactMixin):
|
|
|
173
173
|
response = self._client().post(
|
|
174
174
|
url=self._get_url(),
|
|
175
175
|
data=payload,
|
|
176
|
+
headers={'Content-Type': 'application/json'},
|
|
176
177
|
)
|
|
177
178
|
self._refresh_from_response(response=response)
|
|
178
179
|
return self
|