mlrun 1.6.4rc8__py3-none-any.whl → 1.7.0__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.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +40 -122
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +5 -4
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +47 -257
- mlrun/artifacts/dataset.py +11 -192
- mlrun/artifacts/manager.py +79 -47
- mlrun/artifacts/model.py +31 -159
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +74 -1
- mlrun/common/db/sql_session.py +5 -5
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +45 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +33 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +12 -3
- mlrun/common/model_monitoring/helpers.py +9 -5
- mlrun/{runtimes → common/runtimes}/constants.py +37 -9
- mlrun/common/schemas/__init__.py +31 -5
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +196 -0
- mlrun/common/schemas/artifact.py +25 -4
- mlrun/common/schemas/auth.py +16 -5
- mlrun/common/schemas/background_task.py +1 -1
- mlrun/common/schemas/client_spec.py +4 -2
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +74 -44
- mlrun/common/schemas/frontend_spec.py +15 -7
- mlrun/common/schemas/function.py +12 -1
- mlrun/common/schemas/hub.py +11 -18
- mlrun/common/schemas/memory_reports.py +2 -2
- mlrun/common/schemas/model_monitoring/__init__.py +20 -4
- mlrun/common/schemas/model_monitoring/constants.py +123 -42
- mlrun/common/schemas/model_monitoring/grafana.py +13 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +101 -54
- mlrun/common/schemas/notification.py +71 -14
- mlrun/common/schemas/object.py +2 -2
- mlrun/{model_monitoring/controller_handler.py → common/schemas/pagination.py} +9 -12
- mlrun/common/schemas/pipeline.py +8 -1
- mlrun/common/schemas/project.py +69 -18
- mlrun/common/schemas/runs.py +7 -1
- mlrun/common/schemas/runtime_resource.py +8 -12
- mlrun/common/schemas/schedule.py +4 -4
- mlrun/common/schemas/tag.py +1 -2
- mlrun/common/schemas/workflow.py +12 -4
- mlrun/common/types.py +14 -1
- mlrun/config.py +154 -69
- mlrun/data_types/data_types.py +6 -1
- mlrun/data_types/spark.py +2 -2
- mlrun/data_types/to_pandas.py +67 -37
- mlrun/datastore/__init__.py +6 -8
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +143 -42
- mlrun/datastore/base.py +102 -58
- mlrun/datastore/datastore.py +34 -13
- mlrun/datastore/datastore_profile.py +146 -20
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -4
- mlrun/datastore/google_cloud_storage.py +97 -33
- mlrun/datastore/hdfs.py +56 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +7 -2
- mlrun/datastore/s3.py +34 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +303 -111
- mlrun/datastore/spark_utils.py +31 -2
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +453 -176
- mlrun/datastore/utils.py +72 -58
- mlrun/datastore/v3io.py +6 -1
- mlrun/db/base.py +274 -41
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +893 -225
- mlrun/db/nopdb.py +291 -33
- mlrun/errors.py +36 -6
- mlrun/execution.py +115 -42
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +65 -73
- mlrun/feature_store/common.py +7 -12
- mlrun/feature_store/feature_set.py +76 -55
- mlrun/feature_store/feature_vector.py +39 -31
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +16 -11
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +45 -34
- mlrun/features.py +11 -21
- mlrun/frameworks/_common/artifacts_library.py +9 -9
- mlrun/frameworks/_common/mlrun_interface.py +5 -5
- mlrun/frameworks/_common/model_handler.py +48 -48
- mlrun/frameworks/_common/plan.py +5 -6
- mlrun/frameworks/_common/producer.py +3 -4
- mlrun/frameworks/_common/utils.py +5 -5
- mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
- mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
- mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
- mlrun/frameworks/_ml_common/model_handler.py +24 -24
- mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
- mlrun/frameworks/_ml_common/plan.py +2 -2
- mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/_ml_common/utils.py +4 -4
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
- mlrun/frameworks/huggingface/model_server.py +4 -4
- mlrun/frameworks/lgbm/__init__.py +33 -33
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
- mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
- mlrun/frameworks/lgbm/model_handler.py +10 -10
- mlrun/frameworks/lgbm/model_server.py +6 -6
- mlrun/frameworks/lgbm/utils.py +5 -5
- mlrun/frameworks/onnx/dataset.py +8 -8
- mlrun/frameworks/onnx/mlrun_interface.py +3 -3
- mlrun/frameworks/onnx/model_handler.py +6 -6
- mlrun/frameworks/onnx/model_server.py +7 -7
- mlrun/frameworks/parallel_coordinates.py +6 -6
- mlrun/frameworks/pytorch/__init__.py +18 -18
- mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
- mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
- mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
- mlrun/frameworks/pytorch/model_handler.py +17 -17
- mlrun/frameworks/pytorch/model_server.py +7 -7
- mlrun/frameworks/sklearn/__init__.py +13 -13
- mlrun/frameworks/sklearn/estimator.py +4 -4
- mlrun/frameworks/sklearn/metrics_library.py +14 -14
- mlrun/frameworks/sklearn/mlrun_interface.py +16 -9
- mlrun/frameworks/sklearn/model_handler.py +2 -2
- mlrun/frameworks/tf_keras/__init__.py +10 -7
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
- mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
- mlrun/frameworks/tf_keras/model_handler.py +14 -14
- mlrun/frameworks/tf_keras/model_server.py +6 -6
- mlrun/frameworks/xgboost/__init__.py +13 -13
- mlrun/frameworks/xgboost/model_handler.py +6 -6
- mlrun/k8s_utils.py +61 -17
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +16 -15
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +23 -13
- mlrun/launcher/remote.py +17 -10
- mlrun/lists.py +7 -6
- mlrun/model.py +478 -103
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +163 -371
- mlrun/{runtimes/mpijob/v1alpha1.py → model_monitoring/applications/__init__.py} +9 -15
- mlrun/model_monitoring/applications/_application_steps.py +188 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +354 -0
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +131 -278
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +279 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +507 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +134 -106
- mlrun/model_monitoring/helpers.py +199 -55
- mlrun/model_monitoring/metrics/__init__.py +13 -0
- mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +134 -398
- mlrun/model_monitoring/tracking_policy.py +9 -2
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/__init__.py +6 -6
- mlrun/package/context_handler.py +5 -5
- mlrun/package/packager.py +7 -7
- mlrun/package/packagers/default_packager.py +8 -8
- mlrun/package/packagers/numpy_packagers.py +15 -15
- mlrun/package/packagers/pandas_packagers.py +5 -5
- mlrun/package/packagers/python_standard_library_packagers.py +10 -10
- mlrun/package/packagers_manager.py +19 -23
- mlrun/package/utils/_formatter.py +6 -6
- mlrun/package/utils/_pickler.py +2 -2
- mlrun/package/utils/_supported_format.py +4 -4
- mlrun/package/utils/log_hint_utils.py +2 -2
- mlrun/package/utils/type_hint_utils.py +4 -9
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +24 -203
- mlrun/projects/operations.py +52 -25
- mlrun/projects/pipelines.py +191 -197
- mlrun/projects/project.py +1227 -400
- mlrun/render.py +16 -19
- mlrun/run.py +209 -184
- mlrun/runtimes/__init__.py +83 -15
- mlrun/runtimes/base.py +51 -35
- mlrun/runtimes/daskjob.py +17 -10
- mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
- mlrun/runtimes/databricks_job/databricks_runtime.py +8 -7
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/function_reference.py +1 -1
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +40 -11
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +9 -10
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
- mlrun/runtimes/nuclio/api_gateway.py +769 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/{function.py → nuclio/function.py} +200 -83
- mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
- mlrun/runtimes/{serving.py → nuclio/serving.py} +65 -68
- mlrun/runtimes/pod.py +281 -101
- mlrun/runtimes/remotesparkjob.py +12 -9
- mlrun/runtimes/sparkjob/spark3job.py +67 -51
- mlrun/runtimes/utils.py +41 -75
- mlrun/secrets.py +9 -5
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -7
- mlrun/serving/routers.py +85 -69
- mlrun/serving/server.py +69 -44
- mlrun/serving/states.py +209 -36
- mlrun/serving/utils.py +22 -14
- mlrun/serving/v1_serving.py +6 -7
- mlrun/serving/v2_serving.py +133 -54
- mlrun/track/tracker.py +2 -1
- mlrun/track/tracker_manager.py +3 -3
- mlrun/track/trackers/mlflow_tracker.py +6 -2
- mlrun/utils/async_http.py +6 -8
- mlrun/utils/azure_vault.py +1 -1
- mlrun/utils/clones.py +1 -2
- mlrun/utils/condition_evaluator.py +3 -3
- mlrun/utils/db.py +21 -3
- mlrun/utils/helpers.py +405 -225
- mlrun/utils/http.py +3 -6
- mlrun/utils/logger.py +112 -16
- mlrun/utils/notifications/notification/__init__.py +17 -13
- mlrun/utils/notifications/notification/base.py +50 -2
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +3 -1
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +59 -2
- mlrun/utils/notifications/notification_pusher.py +149 -30
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +208 -0
- mlrun/utils/singleton.py +1 -1
- mlrun/utils/v3io_clients.py +4 -6
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +2 -6
- mlrun-1.7.0.dist-info/METADATA +378 -0
- mlrun-1.7.0.dist-info/RECORD +351 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -273
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -1095
- mlrun/model_monitoring/prometheus.py +0 -219
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -576
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
- mlrun/platforms/other.py +0 -306
- mlrun-1.6.4rc8.dist-info/METADATA +0 -272
- mlrun-1.6.4rc8.dist-info/RECORD +0 -314
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/LICENSE +0 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/top_level.txt +0 -0
|
@@ -13,14 +13,22 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import hashlib
|
|
16
|
-
|
|
16
|
+
import re
|
|
17
|
+
from dataclasses import dataclass, field
|
|
17
18
|
from enum import Enum, IntEnum
|
|
18
19
|
from typing import Optional
|
|
19
20
|
|
|
21
|
+
import mlrun.common.constants
|
|
20
22
|
import mlrun.common.helpers
|
|
21
23
|
from mlrun.common.types import StrEnum
|
|
22
24
|
|
|
23
25
|
|
|
26
|
+
class MonitoringStrEnum(StrEnum):
|
|
27
|
+
@classmethod
|
|
28
|
+
def list(cls):
|
|
29
|
+
return list(map(lambda c: c.value, cls))
|
|
30
|
+
|
|
31
|
+
|
|
24
32
|
class EventFieldType:
|
|
25
33
|
FUNCTION_URI = "function_uri"
|
|
26
34
|
FUNCTION = "function"
|
|
@@ -46,9 +54,11 @@ class EventFieldType:
|
|
|
46
54
|
PREDICTIONS = "predictions"
|
|
47
55
|
NAMED_PREDICTIONS = "named_predictions"
|
|
48
56
|
ERROR_COUNT = "error_count"
|
|
57
|
+
MODEL_ERROR = "model_error"
|
|
49
58
|
ENTITIES = "entities"
|
|
50
59
|
FIRST_REQUEST = "first_request"
|
|
51
60
|
LAST_REQUEST = "last_request"
|
|
61
|
+
LAST_REQUEST_TIMESTAMP = "last_request_timestamp"
|
|
52
62
|
METRIC = "metric"
|
|
53
63
|
METRICS = "metrics"
|
|
54
64
|
BATCH_INTERVALS_DICT = "batch_intervals_dict"
|
|
@@ -72,15 +82,9 @@ class EventFieldType:
|
|
|
72
82
|
FEATURE_SET_URI = "monitoring_feature_set_uri"
|
|
73
83
|
ALGORITHM = "algorithm"
|
|
74
84
|
VALUE = "value"
|
|
75
|
-
DRIFT_DETECTED_THRESHOLD = "drift_detected_threshold"
|
|
76
|
-
POSSIBLE_DRIFT_THRESHOLD = "possible_drift_threshold"
|
|
77
85
|
SAMPLE_PARQUET_PATH = "sample_parquet_path"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class MonitoringStrEnum(StrEnum):
|
|
81
|
-
@classmethod
|
|
82
|
-
def list(cls):
|
|
83
|
-
return list(map(lambda c: c.value, cls))
|
|
86
|
+
TIME = "time"
|
|
87
|
+
TABLE_COLUMN = "table_column"
|
|
84
88
|
|
|
85
89
|
|
|
86
90
|
class FeatureSetFeatures(MonitoringStrEnum):
|
|
@@ -99,12 +103,8 @@ class FeatureSetFeatures(MonitoringStrEnum):
|
|
|
99
103
|
|
|
100
104
|
class ApplicationEvent:
|
|
101
105
|
APPLICATION_NAME = "application_name"
|
|
102
|
-
CURRENT_STATS = "current_stats"
|
|
103
|
-
FEATURE_STATS = "feature_stats"
|
|
104
|
-
SAMPLE_PARQUET_PATH = "sample_parquet_path"
|
|
105
106
|
START_INFER_TIME = "start_infer_time"
|
|
106
107
|
END_INFER_TIME = "end_infer_time"
|
|
107
|
-
LAST_REQUEST = "last_request"
|
|
108
108
|
ENDPOINT_ID = "endpoint_id"
|
|
109
109
|
OUTPUT_STREAM_URI = "output_stream_uri"
|
|
110
110
|
|
|
@@ -114,6 +114,21 @@ class WriterEvent(MonitoringStrEnum):
|
|
|
114
114
|
ENDPOINT_ID = "endpoint_id"
|
|
115
115
|
START_INFER_TIME = "start_infer_time"
|
|
116
116
|
END_INFER_TIME = "end_infer_time"
|
|
117
|
+
EVENT_KIND = "event_kind" # metric or result
|
|
118
|
+
DATA = "data"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class WriterEventKind(MonitoringStrEnum):
|
|
122
|
+
METRIC = "metric"
|
|
123
|
+
RESULT = "result"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class MetricData(MonitoringStrEnum):
|
|
127
|
+
METRIC_NAME = "metric_name"
|
|
128
|
+
METRIC_VALUE = "metric_value"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class ResultData(MonitoringStrEnum):
|
|
117
132
|
RESULT_NAME = "result_name"
|
|
118
133
|
RESULT_VALUE = "result_value"
|
|
119
134
|
RESULT_KIND = "result_kind"
|
|
@@ -138,21 +153,40 @@ class EventKeyMetrics:
|
|
|
138
153
|
REAL_TIME = "real_time"
|
|
139
154
|
|
|
140
155
|
|
|
141
|
-
class
|
|
142
|
-
TSDB = "tsdb"
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
class ModelEndpointTarget:
|
|
156
|
+
class ModelEndpointTarget(MonitoringStrEnum):
|
|
146
157
|
V3IO_NOSQL = "v3io-nosql"
|
|
147
158
|
SQL = "sql"
|
|
148
159
|
|
|
149
160
|
|
|
161
|
+
class StreamKind(MonitoringStrEnum):
|
|
162
|
+
V3IO_STREAM = "v3io_stream"
|
|
163
|
+
KAFKA = "kafka"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class TSDBTarget(MonitoringStrEnum):
|
|
167
|
+
V3IO_TSDB = "v3io-tsdb"
|
|
168
|
+
TDEngine = "tdengine"
|
|
169
|
+
|
|
170
|
+
|
|
150
171
|
class ProjectSecretKeys:
|
|
151
172
|
ENDPOINT_STORE_CONNECTION = "MODEL_MONITORING_ENDPOINT_STORE_CONNECTION"
|
|
152
173
|
ACCESS_KEY = "MODEL_MONITORING_ACCESS_KEY"
|
|
153
|
-
PIPELINES_ACCESS_KEY = "MODEL_MONITORING_PIPELINES_ACCESS_KEY"
|
|
154
|
-
KAFKA_BOOTSTRAP_SERVERS = "KAFKA_BOOTSTRAP_SERVERS"
|
|
155
174
|
STREAM_PATH = "STREAM_PATH"
|
|
175
|
+
TSDB_CONNECTION = "TSDB_CONNECTION"
|
|
176
|
+
|
|
177
|
+
@classmethod
|
|
178
|
+
def mandatory_secrets(cls):
|
|
179
|
+
return [
|
|
180
|
+
cls.ENDPOINT_STORE_CONNECTION,
|
|
181
|
+
cls.STREAM_PATH,
|
|
182
|
+
cls.TSDB_CONNECTION,
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class ModelEndpointTargetSchemas(MonitoringStrEnum):
|
|
187
|
+
V3IO = "v3io"
|
|
188
|
+
MYSQL = "mysql"
|
|
189
|
+
SQLITE = "sqlite"
|
|
156
190
|
|
|
157
191
|
|
|
158
192
|
class ModelMonitoringStoreKinds:
|
|
@@ -162,15 +196,24 @@ class ModelMonitoringStoreKinds:
|
|
|
162
196
|
|
|
163
197
|
class SchedulingKeys:
|
|
164
198
|
LAST_ANALYZED = "last_analyzed"
|
|
199
|
+
ENDPOINT_ID = "endpoint_id"
|
|
200
|
+
APPLICATION_NAME = "application_name"
|
|
201
|
+
UID = "uid"
|
|
165
202
|
|
|
166
203
|
|
|
167
204
|
class FileTargetKind:
|
|
168
205
|
ENDPOINTS = "endpoints"
|
|
169
206
|
EVENTS = "events"
|
|
207
|
+
PREDICTIONS = "predictions"
|
|
170
208
|
STREAM = "stream"
|
|
171
209
|
PARQUET = "parquet"
|
|
172
210
|
APPS_PARQUET = "apps_parquet"
|
|
173
211
|
LOG_STREAM = "log_stream"
|
|
212
|
+
APP_RESULTS = "app_results"
|
|
213
|
+
APP_METRICS = "app_metrics"
|
|
214
|
+
MONITORING_SCHEDULES = "monitoring_schedules"
|
|
215
|
+
MONITORING_APPLICATION = "monitoring_application"
|
|
216
|
+
ERRORS = "errors"
|
|
174
217
|
|
|
175
218
|
|
|
176
219
|
class ModelMonitoringMode(str, Enum):
|
|
@@ -184,29 +227,23 @@ class EndpointType(IntEnum):
|
|
|
184
227
|
LEAF_EP = 3 # end point that is a child of a router
|
|
185
228
|
|
|
186
229
|
|
|
187
|
-
class
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
ERRORS_TOTAL = "errors_total"
|
|
192
|
-
DRIFT_METRICS = "drift_metrics"
|
|
193
|
-
DRIFT_STATUS = "drift_status"
|
|
230
|
+
class MonitoringFunctionNames(MonitoringStrEnum):
|
|
231
|
+
STREAM = "model-monitoring-stream"
|
|
232
|
+
APPLICATION_CONTROLLER = "model-monitoring-controller"
|
|
233
|
+
WRITER = "model-monitoring-writer"
|
|
194
234
|
|
|
195
235
|
|
|
196
|
-
class
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
236
|
+
class V3IOTSDBTables(MonitoringStrEnum):
|
|
237
|
+
APP_RESULTS = "app-results"
|
|
238
|
+
METRICS = "metrics"
|
|
239
|
+
EVENTS = "events"
|
|
240
|
+
ERRORS = "errors"
|
|
201
241
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
MonitoringFunctionNames.BATCH,
|
|
208
|
-
MonitoringFunctionNames.APPLICATION_CONTROLLER,
|
|
209
|
-
]
|
|
242
|
+
|
|
243
|
+
class TDEngineSuperTables(MonitoringStrEnum):
|
|
244
|
+
APP_RESULTS = "app_results"
|
|
245
|
+
METRICS = "metrics"
|
|
246
|
+
PREDICTIONS = "predictions"
|
|
210
247
|
|
|
211
248
|
|
|
212
249
|
@dataclass
|
|
@@ -252,7 +289,7 @@ class EndpointUID:
|
|
|
252
289
|
function_hash_key: str
|
|
253
290
|
model: str
|
|
254
291
|
model_version: str
|
|
255
|
-
uid:
|
|
292
|
+
uid: str = field(init=False)
|
|
256
293
|
|
|
257
294
|
def __post_init__(self):
|
|
258
295
|
function_ref = (
|
|
@@ -285,6 +322,7 @@ class ResultKindApp(Enum):
|
|
|
285
322
|
concept_drift = 1
|
|
286
323
|
model_performance = 2
|
|
287
324
|
system_performance = 3
|
|
325
|
+
mm_app_anomaly = 4
|
|
288
326
|
|
|
289
327
|
|
|
290
328
|
class ResultStatusApp(IntEnum):
|
|
@@ -299,9 +337,52 @@ class ResultStatusApp(IntEnum):
|
|
|
299
337
|
|
|
300
338
|
|
|
301
339
|
class ModelMonitoringAppLabel:
|
|
302
|
-
KEY =
|
|
340
|
+
KEY = mlrun.common.constants.MLRunInternalLabels.mlrun_type
|
|
303
341
|
VAL = "mlrun__model-monitoring-application"
|
|
304
342
|
|
|
343
|
+
def __str__(self) -> str:
|
|
344
|
+
return f"{self.KEY}={self.VAL}"
|
|
345
|
+
|
|
305
346
|
|
|
306
347
|
class ControllerPolicy:
|
|
307
348
|
BASE_PERIOD = "base_period"
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
class HistogramDataDriftApplicationConstants:
|
|
352
|
+
NAME = "histogram-data-drift"
|
|
353
|
+
GENERAL_RESULT_NAME = "general_drift"
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
class PredictionsQueryConstants:
|
|
357
|
+
DEFAULT_AGGREGATION_GRANULARITY = "10m"
|
|
358
|
+
INVOCATIONS = "invocations"
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class SpecialApps:
|
|
362
|
+
MLRUN_INFRA = "mlrun-infra"
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
_RESERVED_FUNCTION_NAMES = MonitoringFunctionNames.list() + [SpecialApps.MLRUN_INFRA]
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
V3IO_MODEL_MONITORING_DB = "v3io"
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class ModelEndpointMonitoringMetricType(StrEnum):
|
|
372
|
+
RESULT = "result"
|
|
373
|
+
METRIC = "metric"
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
_FQN_PART_PATTERN = r"[a-zA-Z0-9_-]+"
|
|
377
|
+
FQN_PATTERN = (
|
|
378
|
+
rf"^(?P<project>{_FQN_PART_PATTERN})\."
|
|
379
|
+
rf"(?P<app>{_FQN_PART_PATTERN})\."
|
|
380
|
+
rf"(?P<type>{ModelEndpointMonitoringMetricType.RESULT}|{ModelEndpointMonitoringMetricType.METRIC})\."
|
|
381
|
+
rf"(?P<name>{_FQN_PART_PATTERN})$"
|
|
382
|
+
)
|
|
383
|
+
FQN_REGEX = re.compile(FQN_PATTERN)
|
|
384
|
+
|
|
385
|
+
# refer to `mlrun.utils.regex.project_name`
|
|
386
|
+
PROJECT_PATTERN = r"^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$"
|
|
387
|
+
|
|
388
|
+
MODEL_ENDPOINT_ID_PATTERN = r"^[a-zA-Z0-9_-]+$"
|
|
@@ -11,12 +11,18 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
#
|
|
15
14
|
|
|
16
|
-
from typing import
|
|
15
|
+
from typing import Optional, Union
|
|
17
16
|
|
|
18
17
|
from pydantic import BaseModel
|
|
19
18
|
|
|
19
|
+
import mlrun.common.types
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GrafanaColumnType(mlrun.common.types.StrEnum):
|
|
23
|
+
NUMBER = "number"
|
|
24
|
+
STRING = "string"
|
|
25
|
+
|
|
20
26
|
|
|
21
27
|
class GrafanaColumn(BaseModel):
|
|
22
28
|
text: str
|
|
@@ -24,18 +30,16 @@ class GrafanaColumn(BaseModel):
|
|
|
24
30
|
|
|
25
31
|
|
|
26
32
|
class GrafanaNumberColumn(GrafanaColumn):
|
|
27
|
-
|
|
28
|
-
type: str = "number"
|
|
33
|
+
type: str = GrafanaColumnType.NUMBER
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
class GrafanaStringColumn(GrafanaColumn):
|
|
32
|
-
|
|
33
|
-
type: str = "string"
|
|
37
|
+
type: str = GrafanaColumnType.STRING
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
class GrafanaTable(BaseModel):
|
|
37
|
-
columns:
|
|
38
|
-
rows:
|
|
41
|
+
columns: list[GrafanaColumn]
|
|
42
|
+
rows: list[list[Optional[Union[float, int, str]]]] = []
|
|
39
43
|
type: str = "table"
|
|
40
44
|
|
|
41
45
|
def add_row(self, *args):
|
|
@@ -49,7 +53,7 @@ class GrafanaDataPoint(BaseModel):
|
|
|
49
53
|
|
|
50
54
|
class GrafanaTimeSeriesTarget(BaseModel):
|
|
51
55
|
target: str
|
|
52
|
-
datapoints:
|
|
56
|
+
datapoints: list[tuple[float, int]] = []
|
|
53
57
|
|
|
54
58
|
def add_data_point(self, data_point: GrafanaDataPoint):
|
|
55
59
|
self.datapoints.append((data_point.value, data_point.timestamp))
|
|
@@ -11,27 +11,35 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
#
|
|
15
14
|
|
|
16
15
|
import enum
|
|
17
16
|
import json
|
|
18
|
-
import
|
|
19
|
-
from typing import Any,
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from typing import Any, NamedTuple, Optional, TypeVar
|
|
20
19
|
|
|
21
|
-
from pydantic import BaseModel, Field, validator
|
|
22
|
-
from pydantic.main import Extra
|
|
20
|
+
from pydantic import BaseModel, Extra, Field, constr, validator
|
|
23
21
|
|
|
22
|
+
# TODO: remove the unused import below after `mlrun.datastore` and `mlrun.utils` usage is removed.
|
|
23
|
+
# At the moment `make lint` fails if this is removed.
|
|
24
24
|
import mlrun.common.model_monitoring
|
|
25
25
|
|
|
26
26
|
from ..object import ObjectKind, ObjectSpec, ObjectStatus
|
|
27
27
|
from .constants import (
|
|
28
|
+
FQN_REGEX,
|
|
29
|
+
MODEL_ENDPOINT_ID_PATTERN,
|
|
30
|
+
PROJECT_PATTERN,
|
|
28
31
|
EndpointType,
|
|
29
32
|
EventFieldType,
|
|
30
33
|
EventKeyMetrics,
|
|
31
34
|
EventLiveStats,
|
|
35
|
+
ModelEndpointMonitoringMetricType,
|
|
32
36
|
ModelMonitoringMode,
|
|
37
|
+
ResultKindApp,
|
|
38
|
+
ResultStatusApp,
|
|
33
39
|
)
|
|
34
40
|
|
|
41
|
+
Model = TypeVar("Model", bound=BaseModel)
|
|
42
|
+
|
|
35
43
|
|
|
36
44
|
class ModelMonitoringStoreKinds:
|
|
37
45
|
# TODO: do changes in examples & demos In 1.5.0 remove
|
|
@@ -40,27 +48,26 @@ class ModelMonitoringStoreKinds:
|
|
|
40
48
|
|
|
41
49
|
|
|
42
50
|
class ModelEndpointMetadata(BaseModel):
|
|
43
|
-
project:
|
|
51
|
+
project: constr(regex=PROJECT_PATTERN)
|
|
52
|
+
uid: constr(regex=MODEL_ENDPOINT_ID_PATTERN)
|
|
44
53
|
labels: Optional[dict] = {}
|
|
45
|
-
uid: Optional[str] = ""
|
|
46
54
|
|
|
47
55
|
class Config:
|
|
48
56
|
extra = Extra.allow
|
|
49
57
|
|
|
50
58
|
@classmethod
|
|
51
|
-
def from_flat_dict(cls, endpoint_dict: dict, json_parse_values:
|
|
59
|
+
def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: list = None):
|
|
52
60
|
"""Create a `ModelEndpointMetadata` object from an endpoint dictionary
|
|
53
61
|
|
|
54
62
|
:param endpoint_dict: Model endpoint dictionary.
|
|
55
63
|
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
56
64
|
dictionary using json.loads().
|
|
57
65
|
"""
|
|
58
|
-
new_object = cls()
|
|
59
66
|
if json_parse_values is None:
|
|
60
67
|
json_parse_values = [EventFieldType.LABELS]
|
|
61
68
|
|
|
62
69
|
return _mapping_attributes(
|
|
63
|
-
|
|
70
|
+
model_class=cls,
|
|
64
71
|
flattened_dictionary=endpoint_dict,
|
|
65
72
|
json_parse_values=json_parse_values,
|
|
66
73
|
)
|
|
@@ -71,8 +78,8 @@ class ModelEndpointSpec(ObjectSpec):
|
|
|
71
78
|
model: Optional[str] = "" # <model_name>:<version>
|
|
72
79
|
model_class: Optional[str] = ""
|
|
73
80
|
model_uri: Optional[str] = ""
|
|
74
|
-
feature_names: Optional[
|
|
75
|
-
label_names: Optional[
|
|
81
|
+
feature_names: Optional[list[str]] = []
|
|
82
|
+
label_names: Optional[list[str]] = []
|
|
76
83
|
stream_path: Optional[str] = ""
|
|
77
84
|
algorithm: Optional[str] = ""
|
|
78
85
|
monitor_configuration: Optional[dict] = {}
|
|
@@ -80,14 +87,13 @@ class ModelEndpointSpec(ObjectSpec):
|
|
|
80
87
|
monitoring_mode: Optional[ModelMonitoringMode] = ModelMonitoringMode.disabled.value
|
|
81
88
|
|
|
82
89
|
@classmethod
|
|
83
|
-
def from_flat_dict(cls, endpoint_dict: dict, json_parse_values:
|
|
90
|
+
def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: list = None):
|
|
84
91
|
"""Create a `ModelEndpointSpec` object from an endpoint dictionary
|
|
85
92
|
|
|
86
93
|
:param endpoint_dict: Model endpoint dictionary.
|
|
87
94
|
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
88
95
|
dictionary using json.loads().
|
|
89
96
|
"""
|
|
90
|
-
new_object = cls()
|
|
91
97
|
if json_parse_values is None:
|
|
92
98
|
json_parse_values = [
|
|
93
99
|
EventFieldType.FEATURE_NAMES,
|
|
@@ -95,23 +101,13 @@ class ModelEndpointSpec(ObjectSpec):
|
|
|
95
101
|
EventFieldType.MONITOR_CONFIGURATION,
|
|
96
102
|
]
|
|
97
103
|
return _mapping_attributes(
|
|
98
|
-
|
|
104
|
+
model_class=cls,
|
|
99
105
|
flattened_dictionary=endpoint_dict,
|
|
100
106
|
json_parse_values=json_parse_values,
|
|
101
107
|
)
|
|
102
108
|
|
|
103
|
-
@validator("monitor_configuration")
|
|
104
|
-
def set_name(cls, monitor_configuration):
|
|
105
|
-
return monitor_configuration or {
|
|
106
|
-
EventFieldType.DRIFT_DETECTED_THRESHOLD: (
|
|
107
|
-
mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.drift_detected
|
|
108
|
-
),
|
|
109
|
-
EventFieldType.POSSIBLE_DRIFT_THRESHOLD: (
|
|
110
|
-
mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.possible_drift
|
|
111
|
-
),
|
|
112
|
-
}
|
|
113
|
-
|
|
114
109
|
@validator("model_uri")
|
|
110
|
+
@classmethod
|
|
115
111
|
def validate_model_uri(cls, model_uri):
|
|
116
112
|
"""Validate that the model uri includes the required prefix"""
|
|
117
113
|
prefix, uri = mlrun.datastore.parse_store_uri(model_uri)
|
|
@@ -123,8 +119,8 @@ class ModelEndpointSpec(ObjectSpec):
|
|
|
123
119
|
|
|
124
120
|
|
|
125
121
|
class Histogram(BaseModel):
|
|
126
|
-
buckets:
|
|
127
|
-
counts:
|
|
122
|
+
buckets: list[float]
|
|
123
|
+
counts: list[int]
|
|
128
124
|
|
|
129
125
|
|
|
130
126
|
class FeatureValues(BaseModel):
|
|
@@ -175,15 +171,15 @@ class ModelEndpointStatus(ObjectStatus):
|
|
|
175
171
|
error_count: Optional[int] = 0
|
|
176
172
|
drift_status: Optional[str] = ""
|
|
177
173
|
drift_measures: Optional[dict] = {}
|
|
178
|
-
metrics: Optional[
|
|
174
|
+
metrics: Optional[dict[str, dict[str, Any]]] = {
|
|
179
175
|
EventKeyMetrics.GENERIC: {
|
|
180
176
|
EventLiveStats.LATENCY_AVG_1H: 0,
|
|
181
177
|
EventLiveStats.PREDICTIONS_PER_SECOND: 0,
|
|
182
178
|
}
|
|
183
179
|
}
|
|
184
|
-
features: Optional[
|
|
185
|
-
children: Optional[
|
|
186
|
-
children_uids: Optional[
|
|
180
|
+
features: Optional[list[Features]] = []
|
|
181
|
+
children: Optional[list[str]] = []
|
|
182
|
+
children_uids: Optional[list[str]] = []
|
|
187
183
|
endpoint_type: Optional[EndpointType] = EndpointType.NODE_EP
|
|
188
184
|
monitoring_feature_set_uri: Optional[str] = ""
|
|
189
185
|
state: Optional[str] = ""
|
|
@@ -192,14 +188,13 @@ class ModelEndpointStatus(ObjectStatus):
|
|
|
192
188
|
extra = Extra.allow
|
|
193
189
|
|
|
194
190
|
@classmethod
|
|
195
|
-
def from_flat_dict(cls, endpoint_dict: dict, json_parse_values:
|
|
191
|
+
def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: list = None):
|
|
196
192
|
"""Create a `ModelEndpointStatus` object from an endpoint dictionary
|
|
197
193
|
|
|
198
194
|
:param endpoint_dict: Model endpoint dictionary.
|
|
199
195
|
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
200
196
|
dictionary using json.loads().
|
|
201
197
|
"""
|
|
202
|
-
new_object = cls()
|
|
203
198
|
if json_parse_values is None:
|
|
204
199
|
json_parse_values = [
|
|
205
200
|
EventFieldType.FEATURE_STATS,
|
|
@@ -211,7 +206,7 @@ class ModelEndpointStatus(ObjectStatus):
|
|
|
211
206
|
EventFieldType.ENDPOINT_TYPE,
|
|
212
207
|
]
|
|
213
208
|
return _mapping_attributes(
|
|
214
|
-
|
|
209
|
+
model_class=cls,
|
|
215
210
|
flattened_dictionary=endpoint_dict,
|
|
216
211
|
json_parse_values=json_parse_values,
|
|
217
212
|
)
|
|
@@ -219,22 +214,13 @@ class ModelEndpointStatus(ObjectStatus):
|
|
|
219
214
|
|
|
220
215
|
class ModelEndpoint(BaseModel):
|
|
221
216
|
kind: ObjectKind = Field(ObjectKind.model_endpoint, const=True)
|
|
222
|
-
metadata: ModelEndpointMetadata
|
|
217
|
+
metadata: ModelEndpointMetadata
|
|
223
218
|
spec: ModelEndpointSpec = ModelEndpointSpec()
|
|
224
219
|
status: ModelEndpointStatus = ModelEndpointStatus()
|
|
225
220
|
|
|
226
221
|
class Config:
|
|
227
222
|
extra = Extra.allow
|
|
228
223
|
|
|
229
|
-
def __init__(self, **data: Any):
|
|
230
|
-
super().__init__(**data)
|
|
231
|
-
if self.metadata.uid is None:
|
|
232
|
-
uid = mlrun.common.model_monitoring.create_model_endpoint_uid(
|
|
233
|
-
function_uri=self.spec.function_uri,
|
|
234
|
-
versioned_model=self.spec.model,
|
|
235
|
-
)
|
|
236
|
-
self.metadata.uid = str(uid)
|
|
237
|
-
|
|
238
224
|
def flat_dict(self):
|
|
239
225
|
"""Generate a flattened `ModelEndpoint` dictionary. The flattened dictionary result is important for storing
|
|
240
226
|
the model endpoint object in the database.
|
|
@@ -275,7 +261,7 @@ class ModelEndpoint(BaseModel):
|
|
|
275
261
|
return flatten_dict
|
|
276
262
|
|
|
277
263
|
@classmethod
|
|
278
|
-
def from_flat_dict(cls, endpoint_dict: dict):
|
|
264
|
+
def from_flat_dict(cls, endpoint_dict: dict) -> "ModelEndpoint":
|
|
279
265
|
"""Create a `ModelEndpoint` object from an endpoint flattened dictionary. Because the provided dictionary
|
|
280
266
|
is flattened, we pass it as is to the subclasses without splitting the keys into spec, metadata, and status.
|
|
281
267
|
|
|
@@ -290,24 +276,85 @@ class ModelEndpoint(BaseModel):
|
|
|
290
276
|
|
|
291
277
|
|
|
292
278
|
class ModelEndpointList(BaseModel):
|
|
293
|
-
endpoints:
|
|
279
|
+
endpoints: list[ModelEndpoint] = []
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class ModelEndpointMonitoringMetric(BaseModel):
|
|
283
|
+
project: str
|
|
284
|
+
app: str
|
|
285
|
+
type: ModelEndpointMonitoringMetricType
|
|
286
|
+
name: str
|
|
287
|
+
full_name: str
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _compose_full_name(
|
|
291
|
+
*,
|
|
292
|
+
project: str,
|
|
293
|
+
app: str,
|
|
294
|
+
name: str,
|
|
295
|
+
type: ModelEndpointMonitoringMetricType = ModelEndpointMonitoringMetricType.RESULT,
|
|
296
|
+
) -> str:
|
|
297
|
+
return ".".join([project, app, type, name])
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _parse_metric_fqn_to_monitoring_metric(fqn: str) -> ModelEndpointMonitoringMetric:
|
|
301
|
+
match = FQN_REGEX.fullmatch(fqn)
|
|
302
|
+
if match is None:
|
|
303
|
+
raise ValueError("The fully qualified name is not in the expected format")
|
|
304
|
+
return ModelEndpointMonitoringMetric.parse_obj(
|
|
305
|
+
match.groupdict() | {"full_name": fqn}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class _MetricPoint(NamedTuple):
|
|
310
|
+
timestamp: datetime
|
|
311
|
+
value: float
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class _ResultPoint(NamedTuple):
|
|
315
|
+
timestamp: datetime
|
|
316
|
+
value: float
|
|
317
|
+
status: ResultStatusApp
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class _ModelEndpointMonitoringMetricValuesBase(BaseModel):
|
|
321
|
+
full_name: str
|
|
322
|
+
type: ModelEndpointMonitoringMetricType
|
|
323
|
+
data: bool
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class ModelEndpointMonitoringMetricValues(_ModelEndpointMonitoringMetricValuesBase):
|
|
327
|
+
type: ModelEndpointMonitoringMetricType = ModelEndpointMonitoringMetricType.METRIC
|
|
328
|
+
values: list[_MetricPoint]
|
|
329
|
+
data: bool = True
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class ModelEndpointMonitoringResultValues(_ModelEndpointMonitoringMetricValuesBase):
|
|
333
|
+
type: ModelEndpointMonitoringMetricType = ModelEndpointMonitoringMetricType.RESULT
|
|
334
|
+
result_kind: ResultKindApp
|
|
335
|
+
values: list[_ResultPoint]
|
|
336
|
+
data: bool = True
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class ModelEndpointMonitoringMetricNoData(_ModelEndpointMonitoringMetricValuesBase):
|
|
340
|
+
full_name: str
|
|
341
|
+
type: ModelEndpointMonitoringMetricType
|
|
342
|
+
data: bool = False
|
|
294
343
|
|
|
295
344
|
|
|
296
345
|
def _mapping_attributes(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
json_parse_values: typing.List = None,
|
|
300
|
-
):
|
|
346
|
+
model_class: type[Model], flattened_dictionary: dict, json_parse_values: list
|
|
347
|
+
) -> Model:
|
|
301
348
|
"""Generate a `BaseModel` object with the provided dictionary attributes.
|
|
302
349
|
|
|
303
|
-
:param
|
|
350
|
+
:param model_class: `BaseModel` class (e.g. `ModelEndpointMetadata`).
|
|
304
351
|
:param flattened_dictionary: Flattened dictionary that contains the model endpoint attributes.
|
|
305
352
|
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
306
353
|
dictionary using json.loads().
|
|
307
354
|
"""
|
|
308
355
|
# Get the fields of the provided base model object. These fields will be used to filter to relevent keys
|
|
309
356
|
# from the flattened dictionary.
|
|
310
|
-
wanted_keys =
|
|
357
|
+
wanted_keys = model_class.__fields__.keys()
|
|
311
358
|
|
|
312
359
|
# Generate a filtered flattened dictionary that will be parsed into the BaseModel object
|
|
313
360
|
dict_to_parse = {}
|
|
@@ -321,7 +368,7 @@ def _mapping_attributes(
|
|
|
321
368
|
else:
|
|
322
369
|
dict_to_parse[field_key] = flattened_dictionary[field_key]
|
|
323
370
|
|
|
324
|
-
return
|
|
371
|
+
return model_class.parse_obj(dict_to_parse)
|
|
325
372
|
|
|
326
373
|
|
|
327
374
|
def _json_loads_if_not_none(field: Any) -> Any:
|