mlrun 1.9.0rc2__py3-none-any.whl → 1.9.0rc4__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/common/schemas/model_monitoring/model_endpoints.py +32 -8
- mlrun/config.py +0 -6
- mlrun/db/base.py +2 -0
- mlrun/db/httpdb.py +37 -20
- mlrun/db/nopdb.py +2 -0
- mlrun/model_monitoring/controller.py +3 -1
- mlrun/model_monitoring/db/tsdb/base.py +3 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +213 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +27 -49
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +35 -30
- mlrun/model_monitoring/stream_processing.py +7 -11
- mlrun/projects/project.py +20 -5
- mlrun/runtimes/nuclio/function.py +1 -1
- mlrun/serving/states.py +6 -3
- mlrun/utils/notifications/notification/webhook.py +18 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.9.0rc2.dist-info → mlrun-1.9.0rc4.dist-info}/METADATA +2 -6
- {mlrun-1.9.0rc2.dist-info → mlrun-1.9.0rc4.dist-info}/RECORD +22 -21
- {mlrun-1.9.0rc2.dist-info → mlrun-1.9.0rc4.dist-info}/WHEEL +1 -1
- {mlrun-1.9.0rc2.dist-info → mlrun-1.9.0rc4.dist-info}/entry_points.txt +0 -0
- {mlrun-1.9.0rc2.dist-info → mlrun-1.9.0rc4.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.9.0rc2.dist-info → mlrun-1.9.0rc4.dist-info}/top_level.txt +0 -0
|
@@ -88,13 +88,18 @@ class ModelEndpointParser(abc.ABC, BaseModel):
|
|
|
88
88
|
|
|
89
89
|
@classmethod
|
|
90
90
|
def from_flat_dict(
|
|
91
|
-
cls,
|
|
91
|
+
cls,
|
|
92
|
+
endpoint_dict: dict,
|
|
93
|
+
json_parse_values: Optional[list] = None,
|
|
94
|
+
validate: bool = True,
|
|
92
95
|
) -> "ModelEndpointParser":
|
|
93
96
|
"""Create a `ModelEndpointParser` object from an endpoint dictionary
|
|
94
97
|
|
|
95
98
|
:param endpoint_dict: Model endpoint dictionary.
|
|
96
99
|
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
97
100
|
dictionary using json.loads().
|
|
101
|
+
:param validate: Whether to validate the flattened dictionary.
|
|
102
|
+
Skip validation to optimize performance when it is safe to do so.
|
|
98
103
|
"""
|
|
99
104
|
if json_parse_values is None:
|
|
100
105
|
json_parse_values = cls.json_parse_values()
|
|
@@ -103,6 +108,7 @@ class ModelEndpointParser(abc.ABC, BaseModel):
|
|
|
103
108
|
model_class=cls,
|
|
104
109
|
flattened_dictionary=endpoint_dict,
|
|
105
110
|
json_parse_values=json_parse_values,
|
|
111
|
+
validate=validate,
|
|
106
112
|
)
|
|
107
113
|
|
|
108
114
|
|
|
@@ -213,17 +219,27 @@ class ModelEndpoint(BaseModel):
|
|
|
213
219
|
return flatten_dict
|
|
214
220
|
|
|
215
221
|
@classmethod
|
|
216
|
-
def from_flat_dict(
|
|
222
|
+
def from_flat_dict(
|
|
223
|
+
cls, endpoint_dict: dict, validate: bool = True
|
|
224
|
+
) -> "ModelEndpoint":
|
|
217
225
|
"""Create a `ModelEndpoint` object from an endpoint flattened dictionary. Because the provided dictionary
|
|
218
226
|
is flattened, we pass it as is to the subclasses without splitting the keys into spec, metadata, and status.
|
|
219
227
|
|
|
220
228
|
:param endpoint_dict: Model endpoint dictionary.
|
|
229
|
+
:param validate: Whether to validate the flattened dictionary.
|
|
230
|
+
Skip validation to optimize performance when it is safe to do so.
|
|
221
231
|
"""
|
|
222
232
|
|
|
223
233
|
return cls(
|
|
224
|
-
metadata=ModelEndpointMetadata.from_flat_dict(
|
|
225
|
-
|
|
226
|
-
|
|
234
|
+
metadata=ModelEndpointMetadata.from_flat_dict(
|
|
235
|
+
endpoint_dict=endpoint_dict, validate=validate
|
|
236
|
+
),
|
|
237
|
+
spec=ModelEndpointSpec.from_flat_dict(
|
|
238
|
+
endpoint_dict=endpoint_dict, validate=validate
|
|
239
|
+
),
|
|
240
|
+
status=ModelEndpointStatus.from_flat_dict(
|
|
241
|
+
endpoint_dict=endpoint_dict, validate=validate
|
|
242
|
+
),
|
|
227
243
|
)
|
|
228
244
|
|
|
229
245
|
def get(self, field, default=None):
|
|
@@ -311,7 +327,10 @@ class ModelEndpointMonitoringMetricNoData(_ModelEndpointMonitoringMetricValuesBa
|
|
|
311
327
|
|
|
312
328
|
|
|
313
329
|
def _mapping_attributes(
|
|
314
|
-
model_class: type[Model],
|
|
330
|
+
model_class: type[Model],
|
|
331
|
+
flattened_dictionary: dict,
|
|
332
|
+
json_parse_values: list,
|
|
333
|
+
validate: bool = True,
|
|
315
334
|
) -> Model:
|
|
316
335
|
"""Generate a `BaseModel` object with the provided dictionary attributes.
|
|
317
336
|
|
|
@@ -319,8 +338,10 @@ def _mapping_attributes(
|
|
|
319
338
|
:param flattened_dictionary: Flattened dictionary that contains the model endpoint attributes.
|
|
320
339
|
:param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
|
|
321
340
|
dictionary using json.loads().
|
|
341
|
+
:param validate: Whether to validate the flattened dictionary.
|
|
342
|
+
Skip validation to optimize performance when it is safe to do so.
|
|
322
343
|
"""
|
|
323
|
-
# Get the fields of the provided base model object. These fields will be used to filter to
|
|
344
|
+
# Get the fields of the provided base model object. These fields will be used to filter to relevant keys
|
|
324
345
|
# from the flattened dictionary.
|
|
325
346
|
wanted_keys = model_class.__fields__.keys()
|
|
326
347
|
|
|
@@ -338,7 +359,10 @@ def _mapping_attributes(
|
|
|
338
359
|
else:
|
|
339
360
|
dict_to_parse[field_key] = None
|
|
340
361
|
|
|
341
|
-
|
|
362
|
+
if validate:
|
|
363
|
+
return model_class.parse_obj(dict_to_parse)
|
|
364
|
+
|
|
365
|
+
return model_class.construct(**dict_to_parse)
|
|
342
366
|
|
|
343
367
|
|
|
344
368
|
def _json_loads_if_not_none(field: Any) -> Any:
|
mlrun/config.py
CHANGED
|
@@ -634,12 +634,6 @@ default_config = {
|
|
|
634
634
|
"offline_storage_path": "model-endpoints/{kind}",
|
|
635
635
|
"parquet_batching_max_events": 10_000,
|
|
636
636
|
"parquet_batching_timeout_secs": timedelta(minutes=1).total_seconds(),
|
|
637
|
-
"tdengine": {
|
|
638
|
-
"run_directly": True,
|
|
639
|
-
# timeout and retry are ignored when run_directly is set to True
|
|
640
|
-
"timeout": 10,
|
|
641
|
-
"retries": 1,
|
|
642
|
-
},
|
|
643
637
|
},
|
|
644
638
|
"secret_stores": {
|
|
645
639
|
# Use only in testing scenarios (such as integration tests) to avoid using k8s for secrets (will use in-memory
|
mlrun/db/base.py
CHANGED
|
@@ -735,6 +735,7 @@ class RunDBInterface(ABC):
|
|
|
735
735
|
start: Optional[datetime.datetime] = None,
|
|
736
736
|
end: Optional[datetime.datetime] = None,
|
|
737
737
|
tsdb_metrics: bool = True,
|
|
738
|
+
metric_list: Optional[list[str]] = None,
|
|
738
739
|
top_level: bool = False,
|
|
739
740
|
uids: Optional[list[str]] = None,
|
|
740
741
|
latest_only: bool = False,
|
|
@@ -750,6 +751,7 @@ class RunDBInterface(ABC):
|
|
|
750
751
|
function_tag: Optional[str] = None,
|
|
751
752
|
endpoint_id: Optional[str] = None,
|
|
752
753
|
tsdb_metrics: bool = True,
|
|
754
|
+
metric_list: Optional[list[str]] = None,
|
|
753
755
|
feature_analysis: bool = False,
|
|
754
756
|
) -> mlrun.common.schemas.ModelEndpoint:
|
|
755
757
|
pass
|
mlrun/db/httpdb.py
CHANGED
|
@@ -1276,8 +1276,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1276
1276
|
:param producer_uri: Return artifacts produced by the requested producer URI. Producer URI usually
|
|
1277
1277
|
points to a run and is used to filter artifacts by the run that produced them when the artifact producer id
|
|
1278
1278
|
is a workflow id (artifact was created as part of a workflow).
|
|
1279
|
-
:param format_:
|
|
1280
|
-
:param limit:
|
|
1279
|
+
:param format_: The format in which to return the artifacts. Default is 'full'.
|
|
1280
|
+
:param limit: Deprecated - Maximum number of artifacts to return (will be removed in 1.10.0).
|
|
1281
1281
|
:param partition_by: Field to group results by. When `partition_by` is specified, the `partition_sort_by`
|
|
1282
1282
|
parameter must be provided as well.
|
|
1283
1283
|
:param rows_per_partition: How many top rows (per sorting defined by `partition_sort_by` and `partition_order`)
|
|
@@ -3584,7 +3584,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3584
3584
|
params = {
|
|
3585
3585
|
"type": type,
|
|
3586
3586
|
"endpoint-id": endpoint_ids,
|
|
3587
|
-
"
|
|
3587
|
+
"events-format": events_format,
|
|
3588
3588
|
}
|
|
3589
3589
|
error_message = (
|
|
3590
3590
|
f"Failed to get model monitoring metrics,"
|
|
@@ -3720,7 +3720,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3720
3720
|
path=path,
|
|
3721
3721
|
body=model_endpoint.json(),
|
|
3722
3722
|
params={
|
|
3723
|
-
"
|
|
3723
|
+
"creation-strategy": creation_strategy,
|
|
3724
3724
|
},
|
|
3725
3725
|
)
|
|
3726
3726
|
return mlrun.common.schemas.ModelEndpoint(**response.json())
|
|
@@ -3750,9 +3750,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3750
3750
|
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
3751
3751
|
path=path,
|
|
3752
3752
|
params={
|
|
3753
|
-
"
|
|
3754
|
-
"
|
|
3755
|
-
"
|
|
3753
|
+
"function-name": function_name,
|
|
3754
|
+
"function-tag": function_tag,
|
|
3755
|
+
"endpoint-id": endpoint_id,
|
|
3756
3756
|
},
|
|
3757
3757
|
)
|
|
3758
3758
|
|
|
@@ -3768,6 +3768,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3768
3768
|
start: Optional[datetime] = None,
|
|
3769
3769
|
end: Optional[datetime] = None,
|
|
3770
3770
|
tsdb_metrics: bool = True,
|
|
3771
|
+
metric_list: Optional[list[str]] = None,
|
|
3771
3772
|
top_level: bool = False,
|
|
3772
3773
|
uids: Optional[list[str]] = None,
|
|
3773
3774
|
latest_only: bool = False,
|
|
@@ -3785,6 +3786,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3785
3786
|
:param start: The start time to filter by.Corresponding to the `created` field.
|
|
3786
3787
|
:param end: The end time to filter by. Corresponding to the `created` field.
|
|
3787
3788
|
:param tsdb_metrics: Whether to include metrics from the time series DB.
|
|
3789
|
+
:param metric_list: List of metrics to include from the time series DB. Defaults to all metrics.
|
|
3790
|
+
If tsdb_metrics=False, this parameter will be ignored and no tsdb metrics
|
|
3791
|
+
will be included.
|
|
3788
3792
|
:param top_level: Whether to return only top level model endpoints.
|
|
3789
3793
|
:param uids: A list of unique ids to filter by.
|
|
3790
3794
|
:param latest_only: Whether to return only the latest model endpoint version.
|
|
@@ -3799,17 +3803,18 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3799
3803
|
path=path,
|
|
3800
3804
|
params={
|
|
3801
3805
|
"name": names,
|
|
3802
|
-
"
|
|
3803
|
-
"
|
|
3804
|
-
"
|
|
3805
|
-
"
|
|
3806
|
+
"model-name": model_name,
|
|
3807
|
+
"model-tag": model_tag,
|
|
3808
|
+
"function-name": function_name,
|
|
3809
|
+
"function-tag": function_tag,
|
|
3806
3810
|
"label": labels,
|
|
3807
3811
|
"start": datetime_to_iso(start),
|
|
3808
3812
|
"end": datetime_to_iso(end),
|
|
3809
|
-
"
|
|
3813
|
+
"tsdb-metrics": tsdb_metrics,
|
|
3814
|
+
"metric": metric_list,
|
|
3810
3815
|
"top-level": top_level,
|
|
3811
3816
|
"uid": uids,
|
|
3812
|
-
"
|
|
3817
|
+
"latest-only": latest_only,
|
|
3813
3818
|
},
|
|
3814
3819
|
)
|
|
3815
3820
|
|
|
@@ -3823,6 +3828,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3823
3828
|
function_tag: Optional[str] = None,
|
|
3824
3829
|
endpoint_id: Optional[str] = None,
|
|
3825
3830
|
tsdb_metrics: bool = True,
|
|
3831
|
+
metric_list: Optional[list[str]] = None,
|
|
3826
3832
|
feature_analysis: bool = False,
|
|
3827
3833
|
) -> mlrun.common.schemas.ModelEndpoint:
|
|
3828
3834
|
"""
|
|
@@ -3834,6 +3840,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3834
3840
|
:param function_tag: The tag of the function
|
|
3835
3841
|
:param endpoint_id: The id of the endpoint
|
|
3836
3842
|
:param tsdb_metrics: Whether to include metrics from the time series DB.
|
|
3843
|
+
:param metric_list: List of metrics to include from the time series DB. Defaults to all metrics.
|
|
3844
|
+
If tsdb_metrics=False, this parameter will be ignored and no tsdb metrics
|
|
3845
|
+
will be included.
|
|
3837
3846
|
:param feature_analysis: Whether to include feature analysis data (feature_stats,
|
|
3838
3847
|
current_stats & drift_measures).
|
|
3839
3848
|
|
|
@@ -3847,11 +3856,12 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3847
3856
|
method=mlrun.common.types.HTTPMethod.GET,
|
|
3848
3857
|
path=path,
|
|
3849
3858
|
params={
|
|
3850
|
-
"
|
|
3851
|
-
"
|
|
3852
|
-
"
|
|
3853
|
-
"
|
|
3854
|
-
"
|
|
3859
|
+
"function-name": function_name,
|
|
3860
|
+
"function-tag": function_tag,
|
|
3861
|
+
"endpoint-id": endpoint_id,
|
|
3862
|
+
"tsdb-metrics": tsdb_metrics,
|
|
3863
|
+
"metric": metric_list,
|
|
3864
|
+
"feature-analysis": feature_analysis,
|
|
3855
3865
|
},
|
|
3856
3866
|
)
|
|
3857
3867
|
|
|
@@ -3879,8 +3889,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3879
3889
|
attributes_keys = list(attributes.keys())
|
|
3880
3890
|
attributes["name"] = name
|
|
3881
3891
|
attributes["project"] = project
|
|
3882
|
-
attributes["
|
|
3883
|
-
attributes["
|
|
3892
|
+
attributes["function-name"] = function_name or None
|
|
3893
|
+
attributes["function-tag"] = function_tag or None
|
|
3884
3894
|
attributes["uid"] = endpoint_id or None
|
|
3885
3895
|
model_endpoint = mlrun.common.schemas.ModelEndpoint.from_flat_dict(attributes)
|
|
3886
3896
|
path = f"projects/{project}/model-endpoints"
|
|
@@ -5089,6 +5099,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5089
5099
|
project = project or config.default_project
|
|
5090
5100
|
labels = self._parse_labels(labels)
|
|
5091
5101
|
|
|
5102
|
+
if limit:
|
|
5103
|
+
# TODO: Remove this in 1.10.0
|
|
5104
|
+
warnings.warn(
|
|
5105
|
+
"'limit' is deprecated and will be removed in 1.10.0. Use 'page' and 'page_size' instead.",
|
|
5106
|
+
FutureWarning,
|
|
5107
|
+
)
|
|
5108
|
+
|
|
5092
5109
|
params = {
|
|
5093
5110
|
"name": name,
|
|
5094
5111
|
"tag": tag,
|
mlrun/db/nopdb.py
CHANGED
|
@@ -632,6 +632,7 @@ class NopDB(RunDBInterface):
|
|
|
632
632
|
start: Optional[datetime.datetime] = None,
|
|
633
633
|
end: Optional[datetime.datetime] = None,
|
|
634
634
|
tsdb_metrics: bool = True,
|
|
635
|
+
metric_list: Optional[list[str]] = None,
|
|
635
636
|
top_level: bool = False,
|
|
636
637
|
uids: Optional[list[str]] = None,
|
|
637
638
|
latest_only: bool = False,
|
|
@@ -646,6 +647,7 @@ class NopDB(RunDBInterface):
|
|
|
646
647
|
function_tag: Optional[str] = None,
|
|
647
648
|
endpoint_id: Optional[str] = None,
|
|
648
649
|
tsdb_metrics: bool = True,
|
|
650
|
+
metric_list: Optional[list[str]] = None,
|
|
649
651
|
feature_analysis: bool = False,
|
|
650
652
|
) -> mlrun.common.schemas.ModelEndpoint:
|
|
651
653
|
pass
|
|
@@ -673,7 +673,9 @@ class MonitoringApplicationController:
|
|
|
673
673
|
"""
|
|
674
674
|
logger.info("Starting monitoring controller chief")
|
|
675
675
|
applications_names = []
|
|
676
|
-
endpoints = self.project_obj.list_model_endpoints(
|
|
676
|
+
endpoints = self.project_obj.list_model_endpoints(
|
|
677
|
+
metric_list=["last_request"]
|
|
678
|
+
).endpoints
|
|
677
679
|
if not endpoints:
|
|
678
680
|
logger.info("No model endpoints found", project=self.project)
|
|
679
681
|
return
|
|
@@ -82,7 +82,8 @@ class TSDBConnector(ABC):
|
|
|
82
82
|
|
|
83
83
|
@abstractmethod
|
|
84
84
|
def delete_tsdb_records(
|
|
85
|
-
self,
|
|
85
|
+
self,
|
|
86
|
+
endpoint_ids: list[str],
|
|
86
87
|
) -> None:
|
|
87
88
|
"""
|
|
88
89
|
Delete model endpoint records from the TSDB connector.
|
|
@@ -332,6 +333,7 @@ class TSDBConnector(ABC):
|
|
|
332
333
|
model_endpoint_objects: list[mlrun.common.schemas.ModelEndpoint],
|
|
333
334
|
project: str,
|
|
334
335
|
run_in_threadpool: Callable,
|
|
336
|
+
metric_list: Optional[list[str]] = None,
|
|
335
337
|
) -> list[mlrun.common.schemas.ModelEndpoint]:
|
|
336
338
|
raise NotImplementedError()
|
|
337
339
|
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Copyright 2025 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import traceback
|
|
16
|
+
from collections.abc import Callable
|
|
17
|
+
from enum import Enum
|
|
18
|
+
from typing import Any, Final, Optional, Union
|
|
19
|
+
|
|
20
|
+
import taosws
|
|
21
|
+
from taosws import TaosStmt
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class _StrEnum(str, Enum):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TimestampPrecision(_StrEnum):
|
|
29
|
+
ms = "ms" # milliseconds
|
|
30
|
+
us = "us" # microseconds
|
|
31
|
+
ns = "ns" # nanoseconds
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_TS_PRECISION_TO_FACTOR_AND_FUNC: Final[
|
|
35
|
+
dict[TimestampPrecision, tuple[int, Callable[[list[int]], taosws.PyColumnView]]]
|
|
36
|
+
] = {
|
|
37
|
+
TimestampPrecision.ms: (10**3, taosws.millis_timestamps_to_column),
|
|
38
|
+
TimestampPrecision.us: (10**6, taosws.micros_timestamps_to_column),
|
|
39
|
+
TimestampPrecision.ns: (10**9, taosws.nanos_timestamps_to_column),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class QueryResult:
|
|
44
|
+
def __init__(self, data, fields):
|
|
45
|
+
self.data = data
|
|
46
|
+
self.fields = fields
|
|
47
|
+
|
|
48
|
+
def __eq__(self, other):
|
|
49
|
+
return self.data == other.data and self.fields == other.fields
|
|
50
|
+
|
|
51
|
+
def __repr__(self):
|
|
52
|
+
return f"QueryResult({self.data}, {self.fields})"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Field:
|
|
56
|
+
def __init__(self, name, type, bytes):
|
|
57
|
+
self.name = name
|
|
58
|
+
self.type = type
|
|
59
|
+
self.bytes = bytes
|
|
60
|
+
|
|
61
|
+
def __eq__(self, other):
|
|
62
|
+
return (
|
|
63
|
+
self.name == other.name
|
|
64
|
+
and self.type == other.type
|
|
65
|
+
and self.bytes == other.bytes
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def __repr__(self):
|
|
69
|
+
return f"Field({self.name}, {self.type}, {self.bytes})"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TDEngineError(Exception):
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ErrorResult:
|
|
77
|
+
def __init__(self, tb, err):
|
|
78
|
+
self.tb = tb
|
|
79
|
+
self.err = err
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _get_timestamp_column(
|
|
83
|
+
values: list, timestamp_precision: TimestampPrecision
|
|
84
|
+
) -> taosws.PyColumnView:
|
|
85
|
+
factor, to_col_func = _TS_PRECISION_TO_FACTOR_AND_FUNC[timestamp_precision]
|
|
86
|
+
timestamps = [round(timestamp.timestamp() * factor) for timestamp in values]
|
|
87
|
+
return to_col_func(timestamps)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def values_to_column(
|
|
91
|
+
values: list,
|
|
92
|
+
column_type: str,
|
|
93
|
+
timestamp_precision: TimestampPrecision = TimestampPrecision.ms,
|
|
94
|
+
) -> taosws.PyColumnView:
|
|
95
|
+
if column_type == "TIMESTAMP":
|
|
96
|
+
return _get_timestamp_column(values, timestamp_precision)
|
|
97
|
+
if column_type == "FLOAT":
|
|
98
|
+
return taosws.floats_to_column(values)
|
|
99
|
+
if column_type == "INT":
|
|
100
|
+
return taosws.ints_to_column(values)
|
|
101
|
+
if column_type.startswith("BINARY"):
|
|
102
|
+
return taosws.binary_to_column(values)
|
|
103
|
+
|
|
104
|
+
raise NotImplementedError(f"Unsupported column type '{column_type}'")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class Statement:
|
|
108
|
+
def __init__(
|
|
109
|
+
self,
|
|
110
|
+
columns: dict[str, str],
|
|
111
|
+
subtable: str,
|
|
112
|
+
values: dict[str, Any],
|
|
113
|
+
timestamp_precision: str = TimestampPrecision.ms,
|
|
114
|
+
) -> None:
|
|
115
|
+
self.columns = columns
|
|
116
|
+
self.subtable = subtable
|
|
117
|
+
self.values = values
|
|
118
|
+
self.timestamp_precision = TimestampPrecision[timestamp_precision]
|
|
119
|
+
|
|
120
|
+
def prepare(self, statement: TaosStmt) -> TaosStmt:
|
|
121
|
+
question_marks = ", ".join("?" * len(self.columns))
|
|
122
|
+
statement.prepare(f"INSERT INTO ? VALUES ({question_marks});")
|
|
123
|
+
statement.set_tbname(self.subtable)
|
|
124
|
+
|
|
125
|
+
bind_params = []
|
|
126
|
+
|
|
127
|
+
for col_name, col_type in self.columns.items():
|
|
128
|
+
val = self.values[col_name]
|
|
129
|
+
bind_params.append(
|
|
130
|
+
values_to_column(
|
|
131
|
+
[val], col_type, timestamp_precision=self.timestamp_precision
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
statement.bind_param(bind_params)
|
|
136
|
+
statement.add_batch()
|
|
137
|
+
return statement
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _run(connection_string, prefix_statements, q, statements, query):
|
|
141
|
+
try:
|
|
142
|
+
conn = taosws.connect(connection_string)
|
|
143
|
+
|
|
144
|
+
for statement in prefix_statements + statements:
|
|
145
|
+
if isinstance(statement, Statement):
|
|
146
|
+
prepared_statement = statement.prepare(conn.statement())
|
|
147
|
+
prepared_statement.execute()
|
|
148
|
+
else:
|
|
149
|
+
conn.execute(statement)
|
|
150
|
+
|
|
151
|
+
if not query:
|
|
152
|
+
q.put(None)
|
|
153
|
+
return
|
|
154
|
+
|
|
155
|
+
res = conn.query(query)
|
|
156
|
+
|
|
157
|
+
# taosws.TaosField is not serializable
|
|
158
|
+
fields = [
|
|
159
|
+
Field(field.name(), field.type(), field.bytes()) for field in res.fields
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
q.put(QueryResult(list(res), fields))
|
|
163
|
+
except Exception as e:
|
|
164
|
+
tb = traceback.format_exc()
|
|
165
|
+
q.put(ErrorResult(tb, e))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class TDEngineConnection:
|
|
169
|
+
def __init__(self, connection_string):
|
|
170
|
+
self._connection_string = connection_string
|
|
171
|
+
self.prefix_statements = []
|
|
172
|
+
|
|
173
|
+
self._conn = taosws.connect(self._connection_string)
|
|
174
|
+
|
|
175
|
+
def run(
|
|
176
|
+
self,
|
|
177
|
+
statements: Optional[Union[str, Statement, list[Union[str, Statement]]]] = None,
|
|
178
|
+
query: Optional[str] = None,
|
|
179
|
+
) -> Optional[QueryResult]:
|
|
180
|
+
statements = statements or []
|
|
181
|
+
if not isinstance(statements, list):
|
|
182
|
+
statements = [statements]
|
|
183
|
+
|
|
184
|
+
for statement in self.prefix_statements + statements:
|
|
185
|
+
if isinstance(statement, Statement):
|
|
186
|
+
try:
|
|
187
|
+
prepared_statement = statement.prepare(self._conn.statement())
|
|
188
|
+
prepared_statement.execute()
|
|
189
|
+
except taosws.Error as e:
|
|
190
|
+
raise TDEngineError(
|
|
191
|
+
f"Failed to run prepared statement `{self._conn.statement()}`: {e}"
|
|
192
|
+
) from e
|
|
193
|
+
else:
|
|
194
|
+
try:
|
|
195
|
+
self._conn.execute(statement)
|
|
196
|
+
except taosws.Error as e:
|
|
197
|
+
raise TDEngineError(
|
|
198
|
+
f"Failed to run statement `{statement}`: {e}"
|
|
199
|
+
) from e
|
|
200
|
+
|
|
201
|
+
if not query:
|
|
202
|
+
return None
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
res = self._conn.query(query)
|
|
206
|
+
except taosws.Error as e:
|
|
207
|
+
raise TDEngineError(f"Failed to run query `{query}`: {e}") from e
|
|
208
|
+
|
|
209
|
+
fields = [
|
|
210
|
+
Field(field.name(), field.type(), field.bytes()) for field in res.fields
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
return QueryResult(list(res), fields)
|
|
@@ -12,17 +12,12 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
import asyncio
|
|
16
15
|
from datetime import datetime, timedelta
|
|
17
16
|
from threading import Lock
|
|
18
17
|
from typing import Callable, Final, Literal, Optional, Union
|
|
19
18
|
|
|
20
19
|
import pandas as pd
|
|
21
20
|
import taosws
|
|
22
|
-
from taoswswrap.tdengine_connection import (
|
|
23
|
-
Statement,
|
|
24
|
-
TDEngineConnection,
|
|
25
|
-
)
|
|
26
21
|
|
|
27
22
|
import mlrun.common.schemas.model_monitoring as mm_schemas
|
|
28
23
|
import mlrun.common.types
|
|
@@ -30,6 +25,10 @@ import mlrun.model_monitoring.db.tsdb.tdengine.schemas as tdengine_schemas
|
|
|
30
25
|
import mlrun.model_monitoring.db.tsdb.tdengine.stream_graph_steps
|
|
31
26
|
from mlrun.datastore.datastore_profile import DatastoreProfile
|
|
32
27
|
from mlrun.model_monitoring.db import TSDBConnector
|
|
28
|
+
from mlrun.model_monitoring.db.tsdb.tdengine.tdengine_connection import (
|
|
29
|
+
Statement,
|
|
30
|
+
TDEngineConnection,
|
|
31
|
+
)
|
|
33
32
|
from mlrun.model_monitoring.helpers import get_invocations_fqn
|
|
34
33
|
from mlrun.utils import logger
|
|
35
34
|
|
|
@@ -75,12 +74,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
75
74
|
|
|
76
75
|
self._init_super_tables()
|
|
77
76
|
|
|
78
|
-
self._run_directly = (
|
|
79
|
-
mlrun.mlconf.model_endpoint_monitoring.tdengine.run_directly
|
|
80
|
-
)
|
|
81
|
-
self._timeout = mlrun.mlconf.model_endpoint_monitoring.tdengine.timeout
|
|
82
|
-
self._retries = mlrun.mlconf.model_endpoint_monitoring.tdengine.retries
|
|
83
|
-
|
|
84
77
|
@property
|
|
85
78
|
def connection(self) -> TDEngineConnection:
|
|
86
79
|
global _connection
|
|
@@ -98,7 +91,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
98
91
|
"""Establish a connection to the TSDB server."""
|
|
99
92
|
logger.debug("Creating a new connection to TDEngine", project=self.project)
|
|
100
93
|
conn = TDEngineConnection(
|
|
101
|
-
self._tdengine_connection_profile.dsn(),
|
|
94
|
+
self._tdengine_connection_profile.dsn(),
|
|
102
95
|
)
|
|
103
96
|
conn.prefix_statements = [f"USE {self.database}"]
|
|
104
97
|
|
|
@@ -126,8 +119,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
126
119
|
self.connection.prefix_statements = []
|
|
127
120
|
self.connection.run(
|
|
128
121
|
statements=f"CREATE DATABASE IF NOT EXISTS {self.database} PRECISION '{self._timestamp_precision}'",
|
|
129
|
-
timeout=self._timeout,
|
|
130
|
-
retries=self._retries,
|
|
131
122
|
)
|
|
132
123
|
self.connection.prefix_statements = [f"USE {self.database}"]
|
|
133
124
|
logger.debug(
|
|
@@ -147,8 +138,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
147
138
|
conn = self.connection
|
|
148
139
|
conn.run(
|
|
149
140
|
statements=create_table_query,
|
|
150
|
-
timeout=self._timeout,
|
|
151
|
-
retries=self._retries,
|
|
152
141
|
)
|
|
153
142
|
|
|
154
143
|
def write_application_event(
|
|
@@ -208,8 +197,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
208
197
|
create_table_sql,
|
|
209
198
|
insert_statement,
|
|
210
199
|
],
|
|
211
|
-
timeout=self._timeout,
|
|
212
|
-
retries=self._retries,
|
|
213
200
|
)
|
|
214
201
|
|
|
215
202
|
@staticmethod
|
|
@@ -313,7 +300,8 @@ class TDEngineConnector(TSDBConnector):
|
|
|
313
300
|
)
|
|
314
301
|
|
|
315
302
|
def delete_tsdb_records(
|
|
316
|
-
self,
|
|
303
|
+
self,
|
|
304
|
+
endpoint_ids: list[str],
|
|
317
305
|
):
|
|
318
306
|
"""
|
|
319
307
|
To delete subtables within TDEngine, we first query the subtables names with the provided endpoint_ids.
|
|
@@ -334,8 +322,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
334
322
|
)
|
|
335
323
|
subtables_result = self.connection.run(
|
|
336
324
|
query=get_subtable_query,
|
|
337
|
-
timeout=self._timeout,
|
|
338
|
-
retries=self._retries,
|
|
339
325
|
)
|
|
340
326
|
subtables.extend([subtable[0] for subtable in subtables_result.data])
|
|
341
327
|
except Exception as e:
|
|
@@ -356,8 +342,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
356
342
|
try:
|
|
357
343
|
self.connection.run(
|
|
358
344
|
statements=drop_statements,
|
|
359
|
-
timeout=delete_timeout or self._timeout,
|
|
360
|
-
retries=self._retries,
|
|
361
345
|
)
|
|
362
346
|
except Exception as e:
|
|
363
347
|
logger.warning(
|
|
@@ -388,8 +372,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
388
372
|
try:
|
|
389
373
|
self.connection.run(
|
|
390
374
|
statements=drop_statements,
|
|
391
|
-
timeout=self._timeout,
|
|
392
|
-
retries=self._retries,
|
|
393
375
|
)
|
|
394
376
|
except Exception as e:
|
|
395
377
|
logger.warning(
|
|
@@ -413,8 +395,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
413
395
|
try:
|
|
414
396
|
table_name = self.connection.run(
|
|
415
397
|
query=query_random_table_name,
|
|
416
|
-
timeout=self._timeout,
|
|
417
|
-
retries=self._retries,
|
|
418
398
|
)
|
|
419
399
|
if len(table_name.data) == 0:
|
|
420
400
|
# no tables were found under the database
|
|
@@ -437,8 +417,6 @@ class TDEngineConnector(TSDBConnector):
|
|
|
437
417
|
try:
|
|
438
418
|
self.connection.run(
|
|
439
419
|
statements=drop_database_query,
|
|
440
|
-
timeout=self._timeout,
|
|
441
|
-
retries=self._retries,
|
|
442
420
|
)
|
|
443
421
|
logger.debug(
|
|
444
422
|
"The TDEngine database has been successfully dropped",
|
|
@@ -531,7 +509,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
531
509
|
logger.debug("Querying TDEngine", query=full_query)
|
|
532
510
|
try:
|
|
533
511
|
query_result = self.connection.run(
|
|
534
|
-
query=full_query,
|
|
512
|
+
query=full_query,
|
|
535
513
|
)
|
|
536
514
|
except taosws.QueryError as e:
|
|
537
515
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
@@ -908,6 +886,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
908
886
|
model_endpoint_objects: list[mlrun.common.schemas.ModelEndpoint],
|
|
909
887
|
project: str,
|
|
910
888
|
run_in_threadpool: Callable,
|
|
889
|
+
metric_list: Optional[list[str]] = None,
|
|
911
890
|
) -> list[mlrun.common.schemas.ModelEndpoint]:
|
|
912
891
|
"""
|
|
913
892
|
Add basic metrics to the model endpoint object.
|
|
@@ -916,24 +895,28 @@ class TDEngineConnector(TSDBConnector):
|
|
|
916
895
|
be filled with the relevant basic metrics.
|
|
917
896
|
:param project: The name of the project.
|
|
918
897
|
:param run_in_threadpool: A function that runs another function in a thread pool.
|
|
898
|
+
:param metric_list: List of metrics to include from the time series DB. Defaults to all metrics.
|
|
919
899
|
|
|
920
900
|
:return: A list of `ModelEndpointMonitoringMetric` objects.
|
|
921
901
|
"""
|
|
922
902
|
|
|
923
903
|
uids = [mep.metadata.uid for mep in model_endpoint_objects]
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
904
|
+
|
|
905
|
+
metric_name_to_function = {
|
|
906
|
+
"error_count": self.get_error_count,
|
|
907
|
+
"last_request": self.get_last_request,
|
|
908
|
+
"avg_latency": self.get_avg_latency,
|
|
909
|
+
"result_status": self.get_drift_status,
|
|
910
|
+
}
|
|
911
|
+
if metric_list is not None:
|
|
912
|
+
for metric_name in list(metric_name_to_function):
|
|
913
|
+
if metric_name not in metric_list:
|
|
914
|
+
del metric_name_to_function[metric_name]
|
|
915
|
+
|
|
916
|
+
metric_name_to_df = {
|
|
917
|
+
metric_name: function(endpoint_ids=uids)
|
|
918
|
+
for metric_name, function in metric_name_to_function.items()
|
|
919
|
+
}
|
|
937
920
|
|
|
938
921
|
def add_metrics(
|
|
939
922
|
mep: mlrun.common.schemas.ModelEndpoint,
|
|
@@ -955,12 +938,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
955
938
|
map(
|
|
956
939
|
lambda mep: add_metrics(
|
|
957
940
|
mep=mep,
|
|
958
|
-
df_dictionary=
|
|
959
|
-
"error_count": error_count_df,
|
|
960
|
-
"last_request": last_request_df,
|
|
961
|
-
"avg_latency": avg_latency_df,
|
|
962
|
-
"result_status": drift_status_df,
|
|
963
|
-
},
|
|
941
|
+
df_dictionary=metric_name_to_df,
|
|
964
942
|
),
|
|
965
943
|
model_endpoint_objects,
|
|
966
944
|
)
|
|
@@ -470,7 +470,8 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
470
470
|
store.rm(tsdb_path, recursive=True)
|
|
471
471
|
|
|
472
472
|
def delete_tsdb_records(
|
|
473
|
-
self,
|
|
473
|
+
self,
|
|
474
|
+
endpoint_ids: list[str],
|
|
474
475
|
):
|
|
475
476
|
logger.debug(
|
|
476
477
|
"Deleting model endpoints resources using the V3IO TSDB connector",
|
|
@@ -1085,6 +1086,7 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
1085
1086
|
model_endpoint_objects: list[mlrun.common.schemas.ModelEndpoint],
|
|
1086
1087
|
project: str,
|
|
1087
1088
|
run_in_threadpool: Callable,
|
|
1089
|
+
metric_list: Optional[list[str]] = None,
|
|
1088
1090
|
) -> list[mlrun.common.schemas.ModelEndpoint]:
|
|
1089
1091
|
"""
|
|
1090
1092
|
Fetch basic metrics from V3IO TSDB and add them to MEP objects.
|
|
@@ -1093,6 +1095,7 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
1093
1095
|
be filled with the relevant basic metrics.
|
|
1094
1096
|
:param project: The name of the project.
|
|
1095
1097
|
:param run_in_threadpool: A function that runs another function in a thread pool.
|
|
1098
|
+
:param metric_list: List of metrics to include from the time series DB. Defaults to all metrics.
|
|
1096
1099
|
|
|
1097
1100
|
:return: A list of `ModelEndpointMonitoringMetric` objects.
|
|
1098
1101
|
"""
|
|
@@ -1104,15 +1107,27 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
1104
1107
|
uids.append(uid)
|
|
1105
1108
|
model_endpoint_objects_by_uid[uid] = model_endpoint_object
|
|
1106
1109
|
|
|
1107
|
-
|
|
1108
|
-
self.get_error_count,
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1110
|
+
metric_name_to_function_and_column_name = {
|
|
1111
|
+
"error_count": (self.get_error_count, "count(error_count)"),
|
|
1112
|
+
"avg_latency": (self.get_avg_latency, "avg(latency)"),
|
|
1113
|
+
"result_status": (self.get_drift_status, "max(result_status)"),
|
|
1114
|
+
}
|
|
1115
|
+
if metric_list is not None:
|
|
1116
|
+
for metric_name in list(metric_name_to_function_and_column_name):
|
|
1117
|
+
if metric_name not in metric_list:
|
|
1118
|
+
del metric_name_to_function_and_column_name[metric_name]
|
|
1119
|
+
|
|
1120
|
+
metric_name_to_result = {}
|
|
1121
|
+
|
|
1122
|
+
for metric_name, (
|
|
1123
|
+
function,
|
|
1124
|
+
_,
|
|
1125
|
+
) in metric_name_to_function_and_column_name.items():
|
|
1126
|
+
metric_name_to_result[metric_name] = await run_in_threadpool(
|
|
1127
|
+
function,
|
|
1128
|
+
endpoint_ids=uids,
|
|
1129
|
+
get_raw=True,
|
|
1130
|
+
)
|
|
1116
1131
|
|
|
1117
1132
|
def add_metric(
|
|
1118
1133
|
metric: str,
|
|
@@ -1128,26 +1143,16 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
1128
1143
|
if mep and value is not None and not math.isnan(value):
|
|
1129
1144
|
setattr(mep.status, metric, value)
|
|
1130
1145
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
)
|
|
1142
|
-
add_metric(
|
|
1143
|
-
"result_status",
|
|
1144
|
-
"max(result_status)",
|
|
1145
|
-
drift_status_res,
|
|
1146
|
-
)
|
|
1147
|
-
|
|
1148
|
-
self._enrich_mep_with_last_request(
|
|
1149
|
-
model_endpoint_objects_by_uid=model_endpoint_objects_by_uid
|
|
1150
|
-
)
|
|
1146
|
+
for metric_name, result in metric_name_to_result.items():
|
|
1147
|
+
add_metric(
|
|
1148
|
+
metric_name,
|
|
1149
|
+
metric_name_to_function_and_column_name[metric_name][1],
|
|
1150
|
+
result,
|
|
1151
|
+
)
|
|
1152
|
+
if metric_list is None or "last_request" in metric_list:
|
|
1153
|
+
self._enrich_mep_with_last_request(
|
|
1154
|
+
model_endpoint_objects_by_uid=model_endpoint_objects_by_uid
|
|
1155
|
+
)
|
|
1151
1156
|
|
|
1152
1157
|
return list(model_endpoint_objects_by_uid.values())
|
|
1153
1158
|
|
|
@@ -384,9 +384,6 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
|
|
|
384
384
|
# Set time for the first request of the current endpoint
|
|
385
385
|
self.first_request[endpoint_id] = timestamp
|
|
386
386
|
|
|
387
|
-
# Set time for the last reqeust of the current endpoint
|
|
388
|
-
self.last_request[endpoint_id] = timestamp
|
|
389
|
-
|
|
390
387
|
if not self.is_valid(
|
|
391
388
|
validation_function=is_not_none,
|
|
392
389
|
field=request_id,
|
|
@@ -413,7 +410,7 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
|
|
|
413
410
|
return None
|
|
414
411
|
|
|
415
412
|
# Convert timestamp to a datetime object
|
|
416
|
-
|
|
413
|
+
timestamp_obj = datetime.datetime.fromisoformat(timestamp)
|
|
417
414
|
|
|
418
415
|
# Separate each model invocation into sub events that will be stored as dictionary
|
|
419
416
|
# in list of events. This list will be used as the body for the storey event.
|
|
@@ -454,16 +451,16 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
|
|
|
454
451
|
EventFieldType.FUNCTION_URI: function_uri,
|
|
455
452
|
EventFieldType.ENDPOINT_NAME: event.get(EventFieldType.MODEL),
|
|
456
453
|
EventFieldType.MODEL_CLASS: model_class,
|
|
457
|
-
EventFieldType.TIMESTAMP:
|
|
454
|
+
EventFieldType.TIMESTAMP: timestamp_obj,
|
|
458
455
|
EventFieldType.ENDPOINT_ID: endpoint_id,
|
|
459
456
|
EventFieldType.REQUEST_ID: request_id,
|
|
460
457
|
EventFieldType.LATENCY: latency,
|
|
461
458
|
EventFieldType.FEATURES: feature,
|
|
462
459
|
EventFieldType.PREDICTION: prediction,
|
|
463
460
|
EventFieldType.FIRST_REQUEST: self.first_request[endpoint_id],
|
|
464
|
-
EventFieldType.LAST_REQUEST:
|
|
461
|
+
EventFieldType.LAST_REQUEST: timestamp,
|
|
465
462
|
EventFieldType.LAST_REQUEST_TIMESTAMP: mlrun.utils.enrich_datetime_with_tz_info(
|
|
466
|
-
|
|
463
|
+
timestamp
|
|
467
464
|
).timestamp(),
|
|
468
465
|
EventFieldType.LABELS: event.get(EventFieldType.LABELS, {}),
|
|
469
466
|
EventFieldType.METRICS: event.get(EventFieldType.METRICS, {}),
|
|
@@ -492,6 +489,7 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
|
|
|
492
489
|
project=self.project,
|
|
493
490
|
endpoint_id=endpoint_id,
|
|
494
491
|
name=endpoint_name,
|
|
492
|
+
tsdb_metrics=False,
|
|
495
493
|
)
|
|
496
494
|
.flat_dict()
|
|
497
495
|
)
|
|
@@ -503,10 +501,6 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
|
|
|
503
501
|
if first_request:
|
|
504
502
|
self.first_request[endpoint_id] = first_request
|
|
505
503
|
|
|
506
|
-
last_request = endpoint_record.get(EventFieldType.LAST_REQUEST)
|
|
507
|
-
if last_request:
|
|
508
|
-
self.last_request[endpoint_id] = last_request
|
|
509
|
-
|
|
510
504
|
# add endpoint to endpoints set
|
|
511
505
|
self.endpoints.add(endpoint_id)
|
|
512
506
|
|
|
@@ -619,6 +613,7 @@ class MapFeatureNames(mlrun.feature_store.steps.MapClass):
|
|
|
619
613
|
project=self.project,
|
|
620
614
|
endpoint_id=endpoint_id,
|
|
621
615
|
name=event[EventFieldType.ENDPOINT_NAME],
|
|
616
|
+
tsdb_metrics=False,
|
|
622
617
|
)
|
|
623
618
|
.flat_dict()
|
|
624
619
|
)
|
|
@@ -692,6 +687,7 @@ class MapFeatureNames(mlrun.feature_store.steps.MapClass):
|
|
|
692
687
|
project=self.project,
|
|
693
688
|
endpoint_id=endpoint_id,
|
|
694
689
|
name=event[EventFieldType.ENDPOINT_NAME],
|
|
690
|
+
tsdb_metrics=False,
|
|
695
691
|
)
|
|
696
692
|
.flat_dict()
|
|
697
693
|
)
|
mlrun/projects/project.py
CHANGED
|
@@ -3796,6 +3796,7 @@ class MlrunProject(ModelObj):
|
|
|
3796
3796
|
uids: Optional[list[str]] = None,
|
|
3797
3797
|
latest_only: bool = False,
|
|
3798
3798
|
tsdb_metrics: bool = True,
|
|
3799
|
+
metric_list: Optional[list[str]] = None,
|
|
3799
3800
|
) -> mlrun.common.schemas.ModelEndpointList:
|
|
3800
3801
|
"""
|
|
3801
3802
|
Returns a list of `ModelEndpoint` objects. Each `ModelEndpoint` object represents the current state of a
|
|
@@ -3825,10 +3826,15 @@ class MlrunProject(ModelObj):
|
|
|
3825
3826
|
or just `"label"` for key existence.
|
|
3826
3827
|
- A comma-separated string formatted as `"label1=value1,label2"` to match entities with
|
|
3827
3828
|
the specified key-value pairs or key existence.
|
|
3828
|
-
:param start:
|
|
3829
|
-
:param end:
|
|
3830
|
-
:param top_level:
|
|
3831
|
-
:param uids:
|
|
3829
|
+
:param start: The start time to filter by.Corresponding to the `created` field.
|
|
3830
|
+
:param end: The end time to filter by. Corresponding to the `created` field.
|
|
3831
|
+
:param top_level: If true will return only routers and endpoint that are NOT children of any router.
|
|
3832
|
+
:param uids: If passed will return a list `ModelEndpoint` object with uid in uids.
|
|
3833
|
+
:param tsdb_metrics: When True, the time series metrics will be added to the output
|
|
3834
|
+
of the resulting.
|
|
3835
|
+
:param metric_list: List of metrics to include from the time series DB. Defaults to all metrics.
|
|
3836
|
+
If tsdb_metrics=False, this parameter will be ignored and no tsdb metrics
|
|
3837
|
+
will be included.
|
|
3832
3838
|
|
|
3833
3839
|
:returns: Returns a list of `ModelEndpoint` objects.
|
|
3834
3840
|
"""
|
|
@@ -3847,6 +3853,7 @@ class MlrunProject(ModelObj):
|
|
|
3847
3853
|
uids=uids,
|
|
3848
3854
|
latest_only=latest_only,
|
|
3849
3855
|
tsdb_metrics=tsdb_metrics,
|
|
3856
|
+
metric_list=metric_list,
|
|
3850
3857
|
)
|
|
3851
3858
|
|
|
3852
3859
|
def run_function(
|
|
@@ -4315,7 +4322,7 @@ class MlrunProject(ModelObj):
|
|
|
4315
4322
|
:param kind: Return artifacts of the requested kind.
|
|
4316
4323
|
:param category: Return artifacts of the requested category.
|
|
4317
4324
|
:param tree: Return artifacts of the requested tree.
|
|
4318
|
-
:param limit: Maximum number of artifacts to return.
|
|
4325
|
+
:param limit: Deprecated - Maximum number of artifacts to return (will be removed in 1.10.0).
|
|
4319
4326
|
:param format_: The format in which to return the artifacts. Default is 'full'.
|
|
4320
4327
|
:param partition_by: Field to group results by. When `partition_by` is specified, the `partition_sort_by`
|
|
4321
4328
|
parameter must be provided as well.
|
|
@@ -4326,6 +4333,14 @@ class MlrunProject(ModelObj):
|
|
|
4326
4333
|
:param partition_order: Order of sorting within partitions - `asc` or `desc`. Default is `desc`.
|
|
4327
4334
|
"""
|
|
4328
4335
|
db = mlrun.db.get_run_db(secrets=self._secrets)
|
|
4336
|
+
|
|
4337
|
+
if limit:
|
|
4338
|
+
# TODO: Remove this in 1.10.0
|
|
4339
|
+
warnings.warn(
|
|
4340
|
+
"'limit' is deprecated and will be removed in 1.10.0. Use 'page' and 'page_size' instead.",
|
|
4341
|
+
FutureWarning,
|
|
4342
|
+
)
|
|
4343
|
+
|
|
4329
4344
|
return db.list_artifacts(
|
|
4330
4345
|
name,
|
|
4331
4346
|
self.metadata.name,
|
|
@@ -1000,7 +1000,7 @@ class RemoteRuntime(KubeResource):
|
|
|
1000
1000
|
else:
|
|
1001
1001
|
http_client_kwargs["json"] = body
|
|
1002
1002
|
try:
|
|
1003
|
-
logger.
|
|
1003
|
+
logger.debug("Invoking function", method=method, path=path)
|
|
1004
1004
|
if not getattr(self, "_http_session", None):
|
|
1005
1005
|
self._http_session = requests.Session()
|
|
1006
1006
|
resp = self._http_session.request(
|
mlrun/serving/states.py
CHANGED
|
@@ -415,15 +415,18 @@ class BaseStep(ModelObj):
|
|
|
415
415
|
steps: list[Union[str, StepToDict, dict[str, Any]]],
|
|
416
416
|
force: bool = False,
|
|
417
417
|
):
|
|
418
|
-
"""
|
|
418
|
+
"""
|
|
419
|
+
Set list of steps as downstream from this step, in the order specified. This will overwrite any existing
|
|
419
420
|
downstream steps.
|
|
420
421
|
|
|
421
422
|
:param steps: list of steps to follow this one
|
|
422
423
|
:param force: whether to overwrite existing downstream steps. If False, this method will fail if any downstream
|
|
423
|
-
|
|
424
|
+
steps have already been defined. Defaults to False.
|
|
425
|
+
|
|
424
426
|
:return: the last step added to the flow
|
|
425
427
|
|
|
426
|
-
example
|
|
428
|
+
example::
|
|
429
|
+
|
|
427
430
|
The below code sets the downstream nodes of step1 by using a list of steps (provided to `set_flow()`) and a
|
|
428
431
|
single step (provided to `to()`), resulting in the graph (step1 -> step2 -> step3 -> step4).
|
|
429
432
|
Notice that using `force=True` is required in case step1 already had downstream nodes (e.g. if the existing
|
|
@@ -16,6 +16,7 @@ import re
|
|
|
16
16
|
import typing
|
|
17
17
|
|
|
18
18
|
import aiohttp
|
|
19
|
+
import orjson
|
|
19
20
|
|
|
20
21
|
import mlrun.common.schemas
|
|
21
22
|
import mlrun.lists
|
|
@@ -86,9 +87,14 @@ class WebhookNotification(NotificationBase):
|
|
|
86
87
|
# we automatically handle it as `ssl=None` for their convenience.
|
|
87
88
|
verify_ssl = verify_ssl and None if url.startswith("https") else None
|
|
88
89
|
|
|
89
|
-
async with aiohttp.ClientSession(
|
|
90
|
+
async with aiohttp.ClientSession(
|
|
91
|
+
json_serialize=self._encoder,
|
|
92
|
+
) as session:
|
|
90
93
|
response = await getattr(session, method)(
|
|
91
|
-
url,
|
|
94
|
+
url,
|
|
95
|
+
headers=headers,
|
|
96
|
+
json=request_body,
|
|
97
|
+
ssl=verify_ssl,
|
|
92
98
|
)
|
|
93
99
|
response.raise_for_status()
|
|
94
100
|
|
|
@@ -128,3 +134,13 @@ class WebhookNotification(NotificationBase):
|
|
|
128
134
|
)
|
|
129
135
|
|
|
130
136
|
return override_body
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def _encoder(self):
|
|
140
|
+
return lambda body: orjson.dumps(
|
|
141
|
+
body,
|
|
142
|
+
option=orjson.OPT_NAIVE_UTC
|
|
143
|
+
| orjson.OPT_SERIALIZE_NUMPY
|
|
144
|
+
| orjson.OPT_NON_STR_KEYS
|
|
145
|
+
| orjson.OPT_SORT_KEYS,
|
|
146
|
+
).decode()
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mlrun
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.0rc4
|
|
4
4
|
Summary: Tracking and config of machine learning runs
|
|
5
5
|
Home-page: https://github.com/mlrun/mlrun
|
|
6
6
|
Author: Yaron Haviv
|
|
@@ -44,7 +44,7 @@ Requires-Dist: semver~=3.0
|
|
|
44
44
|
Requires-Dist: dependency-injector~=4.41
|
|
45
45
|
Requires-Dist: fsspec<2024.7,>=2023.9.2
|
|
46
46
|
Requires-Dist: v3iofs~=0.1.17
|
|
47
|
-
Requires-Dist: storey~=1.
|
|
47
|
+
Requires-Dist: storey~=1.9.0
|
|
48
48
|
Requires-Dist: inflection~=0.5.0
|
|
49
49
|
Requires-Dist: python-dotenv~=1.0
|
|
50
50
|
Requires-Dist: setuptools>=75.2
|
|
@@ -99,7 +99,6 @@ Requires-Dist: ossfs==2023.12.0; extra == "alibaba-oss"
|
|
|
99
99
|
Requires-Dist: oss2==2.18.1; extra == "alibaba-oss"
|
|
100
100
|
Provides-Extra: tdengine
|
|
101
101
|
Requires-Dist: taos-ws-py==0.3.2; extra == "tdengine"
|
|
102
|
-
Requires-Dist: taoswswrap~=0.3.5; extra == "tdengine"
|
|
103
102
|
Provides-Extra: snowflake
|
|
104
103
|
Requires-Dist: snowflake-connector-python~=3.7; extra == "snowflake"
|
|
105
104
|
Provides-Extra: kfp18
|
|
@@ -152,7 +151,6 @@ Requires-Dist: s3fs<2024.7,>=2023.9.2; extra == "all"
|
|
|
152
151
|
Requires-Dist: snowflake-connector-python~=3.7; extra == "all"
|
|
153
152
|
Requires-Dist: sqlalchemy~=1.4; extra == "all"
|
|
154
153
|
Requires-Dist: taos-ws-py==0.3.2; extra == "all"
|
|
155
|
-
Requires-Dist: taoswswrap~=0.3.5; extra == "all"
|
|
156
154
|
Provides-Extra: complete
|
|
157
155
|
Requires-Dist: adlfs==2023.9.0; extra == "complete"
|
|
158
156
|
Requires-Dist: aiobotocore<2.16,>=2.5.0; extra == "complete"
|
|
@@ -184,7 +182,6 @@ Requires-Dist: s3fs<2024.7,>=2023.9.2; extra == "complete"
|
|
|
184
182
|
Requires-Dist: snowflake-connector-python~=3.7; extra == "complete"
|
|
185
183
|
Requires-Dist: sqlalchemy~=1.4; extra == "complete"
|
|
186
184
|
Requires-Dist: taos-ws-py==0.3.2; extra == "complete"
|
|
187
|
-
Requires-Dist: taoswswrap~=0.3.5; extra == "complete"
|
|
188
185
|
Provides-Extra: complete-api
|
|
189
186
|
Requires-Dist: adlfs==2023.9.0; extra == "complete-api"
|
|
190
187
|
Requires-Dist: aiobotocore<2.16,>=2.5.0; extra == "complete-api"
|
|
@@ -229,7 +226,6 @@ Requires-Dist: s3fs<2024.7,>=2023.9.2; extra == "complete-api"
|
|
|
229
226
|
Requires-Dist: snowflake-connector-python~=3.7; extra == "complete-api"
|
|
230
227
|
Requires-Dist: sqlalchemy~=1.4; extra == "complete-api"
|
|
231
228
|
Requires-Dist: taos-ws-py==0.3.2; extra == "complete-api"
|
|
232
|
-
Requires-Dist: taoswswrap~=0.3.5; extra == "complete-api"
|
|
233
229
|
Requires-Dist: timelength~=1.1; extra == "complete-api"
|
|
234
230
|
Requires-Dist: uvicorn~=0.32.1; extra == "complete-api"
|
|
235
231
|
Dynamic: author
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
mlrun/__init__.py,sha256=Cqm9U9eCEdLpMejhU2BEhubu0mHL71igJJIwYa738EA,7450
|
|
2
2
|
mlrun/__main__.py,sha256=0NDzPf9VFRO8KFfGgb8mkGUPIDS285aASV8Hbxs-ND0,45920
|
|
3
|
-
mlrun/config.py,sha256=
|
|
3
|
+
mlrun/config.py,sha256=OYzmm0WrHPiKFPYQ8xrABfYNLzTgnj80_P4iu5H2aQI,71930
|
|
4
4
|
mlrun/errors.py,sha256=LkcbXTLANGdsgo2CRX2pdbyNmt--lMsjGv0XZMgP-Nc,8222
|
|
5
5
|
mlrun/execution.py,sha256=FUktsD3puSFjc3LZJU35b-OmFBrBPBNntViCLQVuwnk,50008
|
|
6
6
|
mlrun/features.py,sha256=ReBaNGsBYXqcbgI012n-SO_j6oHIbk_Vpv0CGPXbUmo,15842
|
|
@@ -75,7 +75,7 @@ mlrun/common/schemas/workflow.py,sha256=6u9niXfXpV-_c2rZL97gFIdAnOfM5WK-OCbrM5Kk
|
|
|
75
75
|
mlrun/common/schemas/model_monitoring/__init__.py,sha256=SxHG-GIdcTEuFxpKzkUdT9zKaU5Xqz9qF1uCwXvZ2z8,1709
|
|
76
76
|
mlrun/common/schemas/model_monitoring/constants.py,sha256=wbNe_n5wX98gD1XQ6jmt97Jh59S9GsE54UBPZl9Pg20,12570
|
|
77
77
|
mlrun/common/schemas/model_monitoring/grafana.py,sha256=THQlLfPBevBksta8p5OaIsBaJtsNSXexLvHrDxOaVns,2095
|
|
78
|
-
mlrun/common/schemas/model_monitoring/model_endpoints.py,sha256=
|
|
78
|
+
mlrun/common/schemas/model_monitoring/model_endpoints.py,sha256=YYFai89qBTnKM8dSUncVD25uwz8QdcTLrEb7vMefyTc,12391
|
|
79
79
|
mlrun/data_types/__init__.py,sha256=wdxGS1PTnaKXiNZ7PYGxxo86OifHH7NYoArIjDJksLA,1054
|
|
80
80
|
mlrun/data_types/data_types.py,sha256=0_oKLC6-sXL2_nnaDMP_HSXB3fD1nJAG4J2Jq6sGNNw,4998
|
|
81
81
|
mlrun/data_types/infer.py,sha256=Ogp3rsENVkjU0GDaGa9J1vjGrvMxgzwbSEuG51nt61E,6477
|
|
@@ -108,10 +108,10 @@ mlrun/datastore/wasbfs/__init__.py,sha256=s5Ul-0kAhYqFjKDR2X0O2vDGDbLQQduElb32Ev
|
|
|
108
108
|
mlrun/datastore/wasbfs/fs.py,sha256=ge8NK__5vTcFT-krI155_8RDUywQw4SIRX6BWATXy9Q,6299
|
|
109
109
|
mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
|
|
110
110
|
mlrun/db/auth_utils.py,sha256=hpg8D2r82oN0BWabuWN04BTNZ7jYMAF242YSUpK7LFM,5211
|
|
111
|
-
mlrun/db/base.py,sha256=
|
|
111
|
+
mlrun/db/base.py,sha256=4ILHlN9vMw3n78qiiTJ1997ykgDKKqxDkLl7lHVVKJg,30814
|
|
112
112
|
mlrun/db/factory.py,sha256=yP2vVmveUE7LYTCHbS6lQIxP9rW--zdISWuPd_I3d_4,2111
|
|
113
|
-
mlrun/db/httpdb.py,sha256=
|
|
114
|
-
mlrun/db/nopdb.py,sha256=
|
|
113
|
+
mlrun/db/httpdb.py,sha256=6CfmyhTG5ZiRUnfayIJN5O1jiYmtarqIY_8FU_gyl0Y,232601
|
|
114
|
+
mlrun/db/nopdb.py,sha256=4TujePdRef5WpZY-TiGL9BmXphilNAypKREiGnqnKtg,27196
|
|
115
115
|
mlrun/feature_store/__init__.py,sha256=SlI845bWt6xX34SXunHHqhmFAR9-5v2ak8N-qpcAPGo,1328
|
|
116
116
|
mlrun/feature_store/api.py,sha256=qKj5Tk6prTab6XWatWhBuPRVp0eJEctoxRMN2wz48vA,32168
|
|
117
117
|
mlrun/feature_store/common.py,sha256=Z7USI-d1fo0iwBMsqMBtJflJfyuiV3BLoDXQPSAoBAs,12826
|
|
@@ -219,10 +219,10 @@ mlrun/launcher/local.py,sha256=775HY-8S9LFUX5ubGXrLO0N1lVh8bn-DHFmNYuNqQPA,11451
|
|
|
219
219
|
mlrun/launcher/remote.py,sha256=rLJW4UAnUT5iUb4BsGBOAV3K4R29a0X4lFtRkVKlyYU,7709
|
|
220
220
|
mlrun/model_monitoring/__init__.py,sha256=ELy7njEtZnz09Dc6PGZSFFEGtnwI15bJNWM3Pj4_YIs,753
|
|
221
221
|
mlrun/model_monitoring/api.py,sha256=LU58dzE4QZiMH23lgiqfI__3m2E3eEZP-DQe2ioUSwM,28317
|
|
222
|
-
mlrun/model_monitoring/controller.py,sha256=
|
|
222
|
+
mlrun/model_monitoring/controller.py,sha256=V5eLOIYsVB6SYMlDQD3--FEW2qN133D1J5I61yzMDn0,36880
|
|
223
223
|
mlrun/model_monitoring/features_drift_table.py,sha256=c6GpKtpOJbuT1u5uMWDL_S-6N4YPOmlktWMqPme3KFY,25308
|
|
224
224
|
mlrun/model_monitoring/helpers.py,sha256=8QsoYRPOVSnR3Lcv99m4XYrp_cR6hSqBUflYSOkJmFQ,21019
|
|
225
|
-
mlrun/model_monitoring/stream_processing.py,sha256=
|
|
225
|
+
mlrun/model_monitoring/stream_processing.py,sha256=Gu3TQzYoNjbreZYI73-F49QpYrod9RZOyGSgininBsA,33373
|
|
226
226
|
mlrun/model_monitoring/tracking_policy.py,sha256=PBIGrUYWrwcE5gwXupBIVzOb0QRRwPJsgQm_yLGQxB4,5595
|
|
227
227
|
mlrun/model_monitoring/writer.py,sha256=ibbhvfSHb8Reqlb7RGFEAUNM4iTyK1gk8-2m46mP6VM,8428
|
|
228
228
|
mlrun/model_monitoring/applications/__init__.py,sha256=xDBxkBjl-whHSG_4t1mLkxiypLH-fzn8TmAW9Mjo2uI,759
|
|
@@ -237,15 +237,16 @@ mlrun/model_monitoring/db/__init__.py,sha256=r47xPGZpIfMuv8J3PQCZTSqVPMhUta4sSJC
|
|
|
237
237
|
mlrun/model_monitoring/db/_schedules.py,sha256=RWn4wtKsIXg668gMLpxO9I8GlkxvPSaA5y7w-wFDcgE,9048
|
|
238
238
|
mlrun/model_monitoring/db/_stats.py,sha256=VVMWLMqG3Us3ozBkLaokJF22Ewv8WKmVE1-OvS_g9vA,6943
|
|
239
239
|
mlrun/model_monitoring/db/tsdb/__init__.py,sha256=4S86V_Ot_skE16SLkw0WwsaAUB0ECH6SoJdp-TIu6s8,4645
|
|
240
|
-
mlrun/model_monitoring/db/tsdb/base.py,sha256=
|
|
240
|
+
mlrun/model_monitoring/db/tsdb/base.py,sha256=mvV9S_adfKaAObzT2w6m4ko30UnRxPrh30eL0dshVyA,26914
|
|
241
241
|
mlrun/model_monitoring/db/tsdb/helpers.py,sha256=0oUXc4aUkYtP2SGP6jTb3uPPKImIUsVsrb9otX9a7O4,1189
|
|
242
242
|
mlrun/model_monitoring/db/tsdb/tdengine/__init__.py,sha256=vgBdsKaXUURKqIf3M0y4sRatmSVA4CQiJs7J5dcVBkQ,620
|
|
243
243
|
mlrun/model_monitoring/db/tsdb/tdengine/schemas.py,sha256=EslhaR65jfeNdD5Ibk-3Hb4e5r5qYPfHb9rTChX3sG0,12689
|
|
244
244
|
mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py,sha256=Uadj0UvAmln2MxDWod-kAzau1uNlqZh981rPhbUH_5M,2857
|
|
245
|
-
mlrun/model_monitoring/db/tsdb/tdengine/
|
|
245
|
+
mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py,sha256=8xo2O_yQrJGNDoYYB3Bwtdwwvzs3U9dT3BtPot0zENQ,6449
|
|
246
|
+
mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=h0ZrNgOwTlBRd_DaYDc6eeVM9f_8CLJMUPEAIrZpbyU,37803
|
|
246
247
|
mlrun/model_monitoring/db/tsdb/v3io/__init__.py,sha256=aL3bfmQsUQ-sbvKGdNihFj8gLCK3mSys0qDcXtYOwgc,616
|
|
247
248
|
mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py,sha256=_-zo9relCDtjGgievxAcAP9gVN9nDWs8BzGtFwTjb9M,6284
|
|
248
|
-
mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py,sha256=
|
|
249
|
+
mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py,sha256=7USfELnW2pwDhjbmFb0nmdqwq7glKfYt-HE7GxPlsEM,46777
|
|
249
250
|
mlrun/model_monitoring/metrics/__init__.py,sha256=6CsTXAxeLbbf8yfCADTaxmiavqwrLEdYFJ-qc5kgDAY,569
|
|
250
251
|
mlrun/model_monitoring/metrics/histogram_distance.py,sha256=E9_WIl2vd6qNvoHVHoFcnuQk3ekbFWOdi8aU7sHrfk4,4724
|
|
251
252
|
mlrun/package/__init__.py,sha256=v7VDyK9kDOOuDvFo4oiGV2fx-vM1KL7fdN9pGLakhUQ,7008
|
|
@@ -270,7 +271,7 @@ mlrun/platforms/iguazio.py,sha256=6VBTq8eQ3mzT96tzjYhAtcMQ2VjF4x8LpIPW5DAcX2Q,13
|
|
|
270
271
|
mlrun/projects/__init__.py,sha256=0Krf0WIKfnZa71WthYOg0SoaTodGg3sV_hK3f_OlTPI,1220
|
|
271
272
|
mlrun/projects/operations.py,sha256=TzPbTYBgmYrjxTKP_wOtBJYFFFwDCQtaVvF1Snr0TfM,20029
|
|
272
273
|
mlrun/projects/pipelines.py,sha256=wud7ezeEmhIJvfYE_wzQbA4ygEfGXHtbOtoOpan6poY,48556
|
|
273
|
-
mlrun/projects/project.py,sha256=
|
|
274
|
+
mlrun/projects/project.py,sha256=NVYJdUHEei2Hnqn4gNepr9rkZOJUOgIzDMMlgmtjvXc,236543
|
|
274
275
|
mlrun/runtimes/__init__.py,sha256=J9Sy2HiyMlztNv6VUurMzF5H2XzttNil8nRsWDsqLyg,8923
|
|
275
276
|
mlrun/runtimes/base.py,sha256=EL14Kmc1vWEjnBPJwLj5hHC6CtRAQHJLmohCD3sFEHo,37855
|
|
276
277
|
mlrun/runtimes/daskjob.py,sha256=JwuGvOiPsxEDHHMMUS4Oie4hLlYYIZwihAl6DjroTY0,19521
|
|
@@ -292,7 +293,7 @@ mlrun/runtimes/mpijob/abstract.py,sha256=JGMjcJ4dvpJbctF6psU9UvYyNCutMxTMgBQeTlz
|
|
|
292
293
|
mlrun/runtimes/mpijob/v1.py,sha256=1XQZC7AIMGX_AQCbApcwpH8I7y39-v0v2O35MvxjXoo,3213
|
|
293
294
|
mlrun/runtimes/nuclio/__init__.py,sha256=gx1kizzKv8pGT5TNloN1js1hdbxqDw3rM90sLVYVffY,794
|
|
294
295
|
mlrun/runtimes/nuclio/api_gateway.py,sha256=vH9ClKVP4Mb24rvA67xPuAvAhX-gAv6vVtjVxyplhdc,26969
|
|
295
|
-
mlrun/runtimes/nuclio/function.py,sha256=
|
|
296
|
+
mlrun/runtimes/nuclio/function.py,sha256=mJ719djvzin7ee9QKoD-DIItuOUvTgrDHhzHgr1Q5zI,54541
|
|
296
297
|
mlrun/runtimes/nuclio/nuclio.py,sha256=sLK8KdGO1LbftlL3HqPZlFOFTAAuxJACZCVl1c0Ha6E,2942
|
|
297
298
|
mlrun/runtimes/nuclio/serving.py,sha256=d0nzPALUYXO4fKFFhxW3hY-_NU-ZhBLWXa2vWIetBRI,33434
|
|
298
299
|
mlrun/runtimes/nuclio/application/__init__.py,sha256=rRs5vasy_G9IyoTpYIjYDafGoL6ifFBKgBtsXn31Atw,614
|
|
@@ -306,7 +307,7 @@ mlrun/serving/remote.py,sha256=gxJkj_J3j-sZcVUbUzbAmJafP6t6y4NVFsu0kWmYngA,18818
|
|
|
306
307
|
mlrun/serving/routers.py,sha256=SY6AsaiSnh8ssXq8hQE2z9MYapOxFOFJBx9QomiZMO8,53915
|
|
307
308
|
mlrun/serving/server.py,sha256=KiNhW0nTV5STZPzR6kEAUFVzCCAX8qv0g9AoCopARrM,23429
|
|
308
309
|
mlrun/serving/serving_wrapper.py,sha256=R670-S6PX_d5ER6jiHtRvacuPyFzQH0mEf2K0sBIIOM,836
|
|
309
|
-
mlrun/serving/states.py,sha256=
|
|
310
|
+
mlrun/serving/states.py,sha256=PaVdgZ8GyE8bxr_-RvuSUINwHuPypJmqaQs27aEPweo,73367
|
|
310
311
|
mlrun/serving/utils.py,sha256=k2EIYDWHUGkE-IBI6T0UNT32fw-KySsccIJM_LObI00,4171
|
|
311
312
|
mlrun/serving/v1_serving.py,sha256=c6J_MtpE-Tqu00-6r4eJOCO6rUasHDal9W2eBIcrl50,11853
|
|
312
313
|
mlrun/serving/v2_serving.py,sha256=b3C5Utv2_AOPrH_hPi3NarjNbAK3kRoeIfqMU4qNuUo,25362
|
|
@@ -338,13 +339,13 @@ mlrun/utils/notifications/notification/git.py,sha256=t2lqRrPRBO4awf_uhxJreH9Cpcb
|
|
|
338
339
|
mlrun/utils/notifications/notification/ipython.py,sha256=9uZvI1uOLFaNuAsfJPXmL3l6dOzFoWdBK5GYNYFAfks,2282
|
|
339
340
|
mlrun/utils/notifications/notification/mail.py,sha256=ZyJ3eqd8simxffQmXzqd3bgbAqp1vij7C6aRJ9h2mgs,6012
|
|
340
341
|
mlrun/utils/notifications/notification/slack.py,sha256=eQvmctTh6wIG5xVOesLLV9S1-UUCu5UEQ9JIJOor3ts,7183
|
|
341
|
-
mlrun/utils/notifications/notification/webhook.py,sha256=
|
|
342
|
+
mlrun/utils/notifications/notification/webhook.py,sha256=zxh8CAlbPnTazsk6r05X5TKwqUZVOH5KBU2fJbzQlG4,5330
|
|
342
343
|
mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
|
|
343
|
-
mlrun/utils/version/version.json,sha256=
|
|
344
|
+
mlrun/utils/version/version.json,sha256=FWbZ7M4qsgWn3DG-fqtofJ0dIpahf_LNjaAXvMs_PE8,88
|
|
344
345
|
mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
|
|
345
|
-
mlrun-1.9.
|
|
346
|
-
mlrun-1.9.
|
|
347
|
-
mlrun-1.9.
|
|
348
|
-
mlrun-1.9.
|
|
349
|
-
mlrun-1.9.
|
|
350
|
-
mlrun-1.9.
|
|
346
|
+
mlrun-1.9.0rc4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
347
|
+
mlrun-1.9.0rc4.dist-info/METADATA,sha256=SWQdOG5QHseA3co1P5RRcPnSOrapdPSHcMS9MJMQuJo,25700
|
|
348
|
+
mlrun-1.9.0rc4.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
|
349
|
+
mlrun-1.9.0rc4.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
|
|
350
|
+
mlrun-1.9.0rc4.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
|
|
351
|
+
mlrun-1.9.0rc4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|