mlrun 1.8.0rc5__py3-none-any.whl → 1.8.0rc9__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 +1 -0
- mlrun/artifacts/__init__.py +1 -1
- mlrun/artifacts/base.py +21 -1
- mlrun/artifacts/document.py +62 -39
- mlrun/artifacts/manager.py +12 -5
- mlrun/common/constants.py +1 -0
- mlrun/common/model_monitoring/__init__.py +0 -2
- mlrun/common/model_monitoring/helpers.py +0 -28
- mlrun/common/schemas/__init__.py +2 -4
- mlrun/common/schemas/alert.py +77 -1
- mlrun/common/schemas/client_spec.py +0 -1
- mlrun/common/schemas/model_monitoring/__init__.py +0 -6
- mlrun/common/schemas/model_monitoring/constants.py +11 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
- mlrun/common/schemas/notification.py +6 -0
- mlrun/common/schemas/project.py +3 -0
- mlrun/config.py +2 -3
- mlrun/datastore/datastore_profile.py +57 -17
- mlrun/datastore/sources.py +1 -2
- mlrun/datastore/store_resources.py +7 -2
- mlrun/datastore/vectorstore.py +99 -62
- mlrun/db/base.py +34 -20
- mlrun/db/httpdb.py +249 -163
- mlrun/db/nopdb.py +40 -17
- mlrun/execution.py +14 -7
- mlrun/feature_store/api.py +1 -0
- mlrun/model.py +3 -0
- mlrun/model_monitoring/__init__.py +3 -2
- mlrun/model_monitoring/api.py +64 -53
- mlrun/model_monitoring/applications/_application_steps.py +3 -1
- mlrun/model_monitoring/applications/base.py +115 -15
- mlrun/model_monitoring/applications/context.py +42 -24
- mlrun/model_monitoring/applications/histogram_data_drift.py +1 -1
- mlrun/model_monitoring/controller.py +43 -37
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/tsdb/base.py +2 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
- mlrun/model_monitoring/helpers.py +78 -66
- mlrun/model_monitoring/stream_processing.py +83 -270
- mlrun/model_monitoring/writer.py +1 -10
- mlrun/projects/pipelines.py +37 -1
- mlrun/projects/project.py +173 -70
- mlrun/run.py +40 -0
- mlrun/runtimes/nuclio/function.py +7 -6
- mlrun/runtimes/nuclio/serving.py +9 -4
- mlrun/serving/routers.py +158 -145
- mlrun/serving/server.py +6 -0
- mlrun/serving/states.py +21 -7
- mlrun/serving/v2_serving.py +94 -68
- mlrun/utils/helpers.py +23 -33
- mlrun/utils/notifications/notification/mail.py +17 -6
- mlrun/utils/notifications/notification_pusher.py +9 -5
- mlrun/utils/regex.py +8 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/METADATA +2 -2
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/RECORD +61 -74
- mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
- mlrun/model_monitoring/db/stores/base/store.py +0 -154
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
- mlrun/model_monitoring/model_endpoint.py +0 -120
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/WHEEL +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/top_level.txt +0 -0
mlrun/serving/v2_serving.py
CHANGED
|
@@ -21,10 +21,9 @@ import mlrun.artifacts
|
|
|
21
21
|
import mlrun.common.model_monitoring.helpers
|
|
22
22
|
import mlrun.common.schemas.model_monitoring
|
|
23
23
|
import mlrun.model_monitoring
|
|
24
|
-
from mlrun.errors import err_to_str
|
|
25
24
|
from mlrun.utils import logger, now_date
|
|
26
25
|
|
|
27
|
-
from ..common.
|
|
26
|
+
from ..common.schemas.model_monitoring import ModelEndpointSchema
|
|
28
27
|
from .server import GraphServer
|
|
29
28
|
from .utils import StepToDict, _extract_input_data, _update_result_body
|
|
30
29
|
|
|
@@ -110,12 +109,6 @@ class V2ModelServer(StepToDict):
|
|
|
110
109
|
self._result_path = result_path
|
|
111
110
|
self._kwargs = kwargs # for to_dict()
|
|
112
111
|
self._params = kwargs
|
|
113
|
-
self._model_logger = (
|
|
114
|
-
_ModelLogPusher(self, context)
|
|
115
|
-
if context and context.stream.enabled
|
|
116
|
-
else None
|
|
117
|
-
)
|
|
118
|
-
|
|
119
112
|
self.metrics = {}
|
|
120
113
|
self.labels = {}
|
|
121
114
|
self.model = None
|
|
@@ -125,6 +118,7 @@ class V2ModelServer(StepToDict):
|
|
|
125
118
|
self._versioned_model_name = None
|
|
126
119
|
self.model_endpoint_uid = None
|
|
127
120
|
self.shard_by_endpoint = shard_by_endpoint
|
|
121
|
+
self._model_logger = None
|
|
128
122
|
|
|
129
123
|
def _load_and_update_state(self):
|
|
130
124
|
try:
|
|
@@ -157,6 +151,11 @@ class V2ModelServer(StepToDict):
|
|
|
157
151
|
self.model_endpoint_uid = _init_endpoint_record(
|
|
158
152
|
graph_server=server, model=self
|
|
159
153
|
)
|
|
154
|
+
self._model_logger = (
|
|
155
|
+
_ModelLogPusher(self, self.context)
|
|
156
|
+
if self.context and self.context.stream.enabled
|
|
157
|
+
else None
|
|
158
|
+
)
|
|
160
159
|
|
|
161
160
|
def get_param(self, key: str, default=None):
|
|
162
161
|
"""get param by key (specified in the model or the function)"""
|
|
@@ -198,13 +197,15 @@ class V2ModelServer(StepToDict):
|
|
|
198
197
|
extra dataitems dictionary
|
|
199
198
|
|
|
200
199
|
"""
|
|
201
|
-
|
|
202
|
-
self.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
200
|
+
if self.model_path:
|
|
201
|
+
model_file, self.model_spec, extra_dataitems = mlrun.artifacts.get_model(
|
|
202
|
+
self.model_path, suffix
|
|
203
|
+
)
|
|
204
|
+
if self.model_spec and self.model_spec.parameters:
|
|
205
|
+
for key, value in self.model_spec.parameters.items():
|
|
206
|
+
self._params[key] = value
|
|
207
|
+
return model_file, extra_dataitems
|
|
208
|
+
return None, None
|
|
208
209
|
|
|
209
210
|
def load(self):
|
|
210
211
|
"""model loading function, see also .get_model() method"""
|
|
@@ -474,7 +475,7 @@ class V2ModelServer(StepToDict):
|
|
|
474
475
|
|
|
475
476
|
|
|
476
477
|
class _ModelLogPusher:
|
|
477
|
-
def __init__(self, model, context, output_stream=None):
|
|
478
|
+
def __init__(self, model: V2ModelServer, context, output_stream=None):
|
|
478
479
|
self.model = model
|
|
479
480
|
self.verbose = context.verbose
|
|
480
481
|
self.hostname = context.stream.hostname
|
|
@@ -496,6 +497,7 @@ class _ModelLogPusher:
|
|
|
496
497
|
"version": self.model.version,
|
|
497
498
|
"host": self.hostname,
|
|
498
499
|
"function_uri": self.function_uri,
|
|
500
|
+
"endpoint_id": self.model.model_endpoint_uid,
|
|
499
501
|
}
|
|
500
502
|
if getattr(self.model, "labels", None):
|
|
501
503
|
base_data["labels"] = self.model.labels
|
|
@@ -567,26 +569,24 @@ def _init_endpoint_record(
|
|
|
567
569
|
"""
|
|
568
570
|
|
|
569
571
|
logger.info("Initializing endpoint records")
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
uid = mlrun.common.model_monitoring.create_model_endpoint_uid(
|
|
583
|
-
function_uri=graph_server.function_uri,
|
|
584
|
-
versioned_model=model.versioned_model_name,
|
|
585
|
-
).uid
|
|
586
|
-
|
|
572
|
+
if not model.model_spec:
|
|
573
|
+
model.get_model()
|
|
574
|
+
if model.model_spec:
|
|
575
|
+
model_name = model.model_spec.metadata.key
|
|
576
|
+
model_uid = model.model_spec.metadata.uid
|
|
577
|
+
model_tag = model.model_spec.tag
|
|
578
|
+
model_labels = model.model_spec.labels # todo : check if we still need this
|
|
579
|
+
else:
|
|
580
|
+
model_name = None
|
|
581
|
+
model_uid = None
|
|
582
|
+
model_tag = None
|
|
583
|
+
model_labels = {}
|
|
587
584
|
try:
|
|
588
585
|
model_ep = mlrun.get_run_db().get_model_endpoint(
|
|
589
|
-
project=project,
|
|
586
|
+
project=graph_server.project,
|
|
587
|
+
name=model.name,
|
|
588
|
+
function_name=graph_server.function_name,
|
|
589
|
+
function_tag=graph_server.function_tag or "latest",
|
|
590
590
|
)
|
|
591
591
|
except mlrun.errors.MLRunNotFoundError:
|
|
592
592
|
model_ep = None
|
|
@@ -596,62 +596,88 @@ def _init_endpoint_record(
|
|
|
596
596
|
)
|
|
597
597
|
return
|
|
598
598
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
599
|
+
function = mlrun.get_run_db().get_function(
|
|
600
|
+
name=graph_server.function_name,
|
|
601
|
+
project=graph_server.project,
|
|
602
|
+
tag=graph_server.function_tag or "latest",
|
|
603
|
+
)
|
|
604
|
+
function_uid = function.get("metadata", {}).get("uid")
|
|
605
|
+
if not model_ep and model.context.server.track_models:
|
|
606
|
+
logger.info(
|
|
607
|
+
"Creating a new model endpoint record",
|
|
608
|
+
name=model.name,
|
|
609
|
+
project=graph_server.project,
|
|
610
|
+
function_name=graph_server.function_name,
|
|
611
|
+
function_tag=graph_server.function_tag or "latest",
|
|
612
|
+
function_uid=function_uid,
|
|
613
|
+
model_name=model_name,
|
|
614
|
+
model_uid=model_uid,
|
|
615
|
+
model_class=model.__class__.__name__,
|
|
616
|
+
model_tag=model_tag,
|
|
617
|
+
)
|
|
618
|
+
model_ep = mlrun.common.schemas.ModelEndpoint(
|
|
602
619
|
metadata=mlrun.common.schemas.ModelEndpointMetadata(
|
|
603
|
-
project=project,
|
|
620
|
+
project=graph_server.project,
|
|
621
|
+
labels=model_labels,
|
|
622
|
+
name=model.name,
|
|
623
|
+
endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP,
|
|
604
624
|
),
|
|
605
625
|
spec=mlrun.common.schemas.ModelEndpointSpec(
|
|
606
|
-
|
|
607
|
-
|
|
626
|
+
function_name=graph_server.function_name,
|
|
627
|
+
function_uid=function_uid,
|
|
628
|
+
function_tag=graph_server.function_tag or "latest",
|
|
629
|
+
model_name=model_name,
|
|
630
|
+
model_uid=model_uid,
|
|
608
631
|
model_class=model.__class__.__name__,
|
|
609
|
-
model_uri=model.model_path,
|
|
610
|
-
stream_path=model.context.stream.stream_uri,
|
|
611
|
-
active=True,
|
|
612
|
-
monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled,
|
|
613
632
|
),
|
|
614
633
|
status=mlrun.common.schemas.ModelEndpointStatus(
|
|
615
|
-
|
|
634
|
+
monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
635
|
+
if model.context.server.track_models
|
|
636
|
+
else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled,
|
|
616
637
|
),
|
|
617
638
|
)
|
|
618
|
-
|
|
619
639
|
db = mlrun.get_run_db()
|
|
620
|
-
db.create_model_endpoint(
|
|
621
|
-
project=project,
|
|
622
|
-
endpoint_id=uid,
|
|
623
|
-
model_endpoint=model_endpoint.dict(),
|
|
624
|
-
)
|
|
640
|
+
model_ep = db.create_model_endpoint(model_endpoint=model_ep)
|
|
625
641
|
|
|
626
642
|
elif model_ep:
|
|
627
643
|
attributes = {}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
644
|
+
if function_uid != model_ep.spec.function_uid:
|
|
645
|
+
attributes[ModelEndpointSchema.FUNCTION_UID] = function_uid
|
|
646
|
+
if model_name != model_ep.spec.model_name:
|
|
647
|
+
attributes[ModelEndpointSchema.MODEL_NAME] = model_name
|
|
648
|
+
if model_uid != model_ep.spec.model_uid:
|
|
649
|
+
attributes[ModelEndpointSchema.MODEL_UID] = model_uid
|
|
650
|
+
if model_tag != model_ep.spec.model_tag:
|
|
651
|
+
attributes[ModelEndpointSchema.MODEL_TAG] = model_tag
|
|
652
|
+
if model_labels != model_ep.metadata.labels:
|
|
653
|
+
attributes[ModelEndpointSchema.LABELS] = model_labels
|
|
654
|
+
if model.__class__.__name__ != model_ep.spec.model_class:
|
|
655
|
+
attributes[ModelEndpointSchema.MODEL_CLASS] = model.__class__.__name__
|
|
635
656
|
if (
|
|
636
|
-
model_ep.
|
|
657
|
+
model_ep.status.monitoring_mode
|
|
637
658
|
== mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
638
659
|
) != model.context.server.track_models:
|
|
639
|
-
attributes[
|
|
660
|
+
attributes[ModelEndpointSchema.MONITORING_MODE] = (
|
|
640
661
|
mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
641
662
|
if model.context.server.track_models
|
|
642
663
|
else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled
|
|
643
664
|
)
|
|
644
665
|
if attributes:
|
|
645
|
-
db = mlrun.get_run_db()
|
|
646
|
-
db.patch_model_endpoint(
|
|
647
|
-
project=project,
|
|
648
|
-
endpoint_id=uid,
|
|
649
|
-
attributes=attributes,
|
|
650
|
-
)
|
|
651
666
|
logger.info(
|
|
652
667
|
"Updating model endpoint attributes",
|
|
653
668
|
attributes=attributes,
|
|
654
|
-
|
|
669
|
+
project=model_ep.metadata.project,
|
|
670
|
+
name=model_ep.metadata.name,
|
|
671
|
+
function_name=model_ep.spec.function_name,
|
|
655
672
|
)
|
|
673
|
+
db = mlrun.get_run_db()
|
|
674
|
+
model_ep = db.patch_model_endpoint(
|
|
675
|
+
project=model_ep.metadata.project,
|
|
676
|
+
name=model_ep.metadata.name,
|
|
677
|
+
endpoint_id=model_ep.metadata.uid,
|
|
678
|
+
attributes=attributes,
|
|
679
|
+
)
|
|
680
|
+
else:
|
|
681
|
+
return None
|
|
656
682
|
|
|
657
|
-
return uid
|
|
683
|
+
return model_ep.metadata.uid
|
mlrun/utils/helpers.py
CHANGED
|
@@ -670,8 +670,8 @@ def dict_to_json(struct):
|
|
|
670
670
|
|
|
671
671
|
def parse_artifact_uri(uri, default_project=""):
|
|
672
672
|
"""
|
|
673
|
-
Parse artifact URI into project, key, tag, iter, tree
|
|
674
|
-
URI format: [<project>/]<key>[#<iter>][:<tag>][@<tree>]
|
|
673
|
+
Parse artifact URI into project, key, tag, iter, tree, uid
|
|
674
|
+
URI format: [<project>/]<key>[#<iter>][:<tag>][@<tree>][^<uid>]
|
|
675
675
|
|
|
676
676
|
:param uri: uri to parse
|
|
677
677
|
:param default_project: default project name if not in URI
|
|
@@ -681,6 +681,7 @@ def parse_artifact_uri(uri, default_project=""):
|
|
|
681
681
|
[2] = iteration
|
|
682
682
|
[3] = tag
|
|
683
683
|
[4] = tree
|
|
684
|
+
[5] = uid
|
|
684
685
|
"""
|
|
685
686
|
uri_pattern = mlrun.utils.regex.artifact_uri_pattern
|
|
686
687
|
match = re.match(uri_pattern, uri)
|
|
@@ -705,6 +706,7 @@ def parse_artifact_uri(uri, default_project=""):
|
|
|
705
706
|
iteration,
|
|
706
707
|
group_dict["tag"],
|
|
707
708
|
group_dict["tree"],
|
|
709
|
+
group_dict["uid"],
|
|
708
710
|
)
|
|
709
711
|
|
|
710
712
|
|
|
@@ -719,7 +721,9 @@ def generate_object_uri(project, name, tag=None, hash_key=None):
|
|
|
719
721
|
return uri
|
|
720
722
|
|
|
721
723
|
|
|
722
|
-
def generate_artifact_uri(
|
|
724
|
+
def generate_artifact_uri(
|
|
725
|
+
project, key, tag=None, iter=None, tree=None, uid=None
|
|
726
|
+
) -> str:
|
|
723
727
|
artifact_uri = f"{project}/{key}"
|
|
724
728
|
if iter is not None:
|
|
725
729
|
artifact_uri = f"{artifact_uri}#{iter}"
|
|
@@ -727,6 +731,8 @@ def generate_artifact_uri(project, key, tag=None, iter=None, tree=None):
|
|
|
727
731
|
artifact_uri = f"{artifact_uri}:{tag}"
|
|
728
732
|
if tree is not None:
|
|
729
733
|
artifact_uri = f"{artifact_uri}@{tree}"
|
|
734
|
+
if uid is not None:
|
|
735
|
+
artifact_uri = f"{artifact_uri}^{uid}"
|
|
730
736
|
return artifact_uri
|
|
731
737
|
|
|
732
738
|
|
|
@@ -956,36 +962,6 @@ def fill_function_hash(function_dict, tag=""):
|
|
|
956
962
|
return fill_object_hash(function_dict, "hash", tag)
|
|
957
963
|
|
|
958
964
|
|
|
959
|
-
def fill_model_endpoint_hash(
|
|
960
|
-
model_endpoint: mlrun.common.schemas.ModelEndpointV2,
|
|
961
|
-
created_time: typing.Union[str, datetime],
|
|
962
|
-
) -> str:
|
|
963
|
-
"""
|
|
964
|
-
Fill the model endpoint uid field in the model endpoint object and returns it.
|
|
965
|
-
The uid is generated by hashing the following model endpoint fields:
|
|
966
|
-
- name
|
|
967
|
-
- model_tag
|
|
968
|
-
- function_name
|
|
969
|
-
- project
|
|
970
|
-
- created_time
|
|
971
|
-
"""
|
|
972
|
-
|
|
973
|
-
name = model_endpoint.metadata.name
|
|
974
|
-
model_tag = model_endpoint.spec.model_tag
|
|
975
|
-
function_name = model_endpoint.spec.function_name
|
|
976
|
-
project = model_endpoint.metadata.project
|
|
977
|
-
created_time = (
|
|
978
|
-
created_time
|
|
979
|
-
if isinstance(created_time, str)
|
|
980
|
-
else created_time.isoformat(sep=" ", timespec="microseconds")
|
|
981
|
-
)
|
|
982
|
-
|
|
983
|
-
unique_string = f"{name}_{model_tag}_{function_name}_{project}_{created_time}"
|
|
984
|
-
uid = hashlib.sha1(unique_string.encode("utf-8")).hexdigest()
|
|
985
|
-
model_endpoint.metadata.uid = uid
|
|
986
|
-
return uid
|
|
987
|
-
|
|
988
|
-
|
|
989
965
|
def retry_until_successful(
|
|
990
966
|
backoff: int, timeout: int, logger, verbose: bool, _function, *args, **kwargs
|
|
991
967
|
):
|
|
@@ -1886,3 +1862,17 @@ def run_with_retry(
|
|
|
1886
1862
|
if attempt == retry_count:
|
|
1887
1863
|
raise
|
|
1888
1864
|
raise last_exception
|
|
1865
|
+
|
|
1866
|
+
|
|
1867
|
+
def join_urls(base_url: Optional[str], path: Optional[str]) -> str:
|
|
1868
|
+
"""
|
|
1869
|
+
Joins a base URL with a path, ensuring proper handling of slashes.
|
|
1870
|
+
|
|
1871
|
+
:param base_url: The base URL (e.g., "http://example.com").
|
|
1872
|
+
:param path: The path to append to the base URL (e.g., "/path/to/resource").
|
|
1873
|
+
|
|
1874
|
+
:return: A unified URL with exactly one slash between base_url and path.
|
|
1875
|
+
"""
|
|
1876
|
+
if base_url is None:
|
|
1877
|
+
base_url = ""
|
|
1878
|
+
return f"{base_url.rstrip('/')}/{path.lstrip('/')}" if path else base_url
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import re
|
|
15
15
|
import typing
|
|
16
|
-
from email.
|
|
16
|
+
from email.mime.multipart import MIMEMultipart
|
|
17
|
+
from email.mime.text import MIMEText
|
|
17
18
|
|
|
18
19
|
import aiosmtplib
|
|
19
20
|
|
|
@@ -69,9 +70,19 @@ class MailNotification(base.NotificationBase):
|
|
|
69
70
|
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
70
71
|
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
71
72
|
):
|
|
72
|
-
|
|
73
|
-
self.params.
|
|
74
|
-
|
|
73
|
+
self.params["subject"] = f"[{severity}] {message}"
|
|
74
|
+
message_body_override = self.params.get("message_body_override", None)
|
|
75
|
+
|
|
76
|
+
runs_html = self._get_html(
|
|
77
|
+
message, severity, runs, custom_html, alert, event_data
|
|
78
|
+
)
|
|
79
|
+
self.params["body"] = runs_html
|
|
80
|
+
|
|
81
|
+
if message_body_override:
|
|
82
|
+
self.params["body"] = message_body_override.replace(
|
|
83
|
+
"{{ runs }}", runs_html
|
|
84
|
+
).replace("{{runs}}", runs_html)
|
|
85
|
+
|
|
75
86
|
await self._send_email(**self.params)
|
|
76
87
|
|
|
77
88
|
@classmethod
|
|
@@ -146,11 +157,11 @@ class MailNotification(base.NotificationBase):
|
|
|
146
157
|
**kwargs,
|
|
147
158
|
):
|
|
148
159
|
# Create the email message
|
|
149
|
-
message =
|
|
160
|
+
message = MIMEMultipart("alternative")
|
|
150
161
|
message["From"] = sender_address
|
|
151
162
|
message["To"] = email_addresses
|
|
152
163
|
message["Subject"] = subject
|
|
153
|
-
message.
|
|
164
|
+
message.attach(MIMEText(body, "html"))
|
|
154
165
|
|
|
155
166
|
# Send the email
|
|
156
167
|
await aiosmtplib.send(
|
|
@@ -21,7 +21,7 @@ import typing
|
|
|
21
21
|
from concurrent.futures import ThreadPoolExecutor
|
|
22
22
|
|
|
23
23
|
import mlrun.common.constants as mlrun_constants
|
|
24
|
-
import mlrun.common.runtimes.constants
|
|
24
|
+
import mlrun.common.runtimes.constants as runtimes_constants
|
|
25
25
|
import mlrun.common.schemas
|
|
26
26
|
import mlrun.config
|
|
27
27
|
import mlrun.db.base
|
|
@@ -226,7 +226,7 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
226
226
|
for when_state in when_states:
|
|
227
227
|
if when_state == run_state:
|
|
228
228
|
if (
|
|
229
|
-
run_state ==
|
|
229
|
+
run_state == runtimes_constants.RunStates.completed
|
|
230
230
|
and evaluate_condition_in_separate_process(
|
|
231
231
|
notification.condition,
|
|
232
232
|
context={
|
|
@@ -234,7 +234,11 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
234
234
|
"notification": notification.to_dict(),
|
|
235
235
|
},
|
|
236
236
|
)
|
|
237
|
-
) or run_state in [
|
|
237
|
+
) or run_state in [
|
|
238
|
+
runtimes_constants.RunStates.error,
|
|
239
|
+
runtimes_constants.RunStates.aborted,
|
|
240
|
+
runtimes_constants.RunStates.running,
|
|
241
|
+
]:
|
|
238
242
|
return True
|
|
239
243
|
|
|
240
244
|
return False
|
|
@@ -441,7 +445,7 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
441
445
|
_run["step_kind"] = _step.step_type
|
|
442
446
|
if _step.skipped:
|
|
443
447
|
_run.setdefault("status", {})["state"] = (
|
|
444
|
-
|
|
448
|
+
runtimes_constants.RunStates.skipped
|
|
445
449
|
)
|
|
446
450
|
steps.append(_run)
|
|
447
451
|
|
|
@@ -468,7 +472,7 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
468
472
|
if _step.skipped:
|
|
469
473
|
state = mlrun.common.schemas.FunctionState.skipped
|
|
470
474
|
else:
|
|
471
|
-
state =
|
|
475
|
+
state = runtimes_constants.PodPhases.pod_phase_to_run_state(
|
|
472
476
|
pod_phase
|
|
473
477
|
)
|
|
474
478
|
function["status"] = {"state": state}
|
mlrun/utils/regex.py
CHANGED
|
@@ -96,7 +96,14 @@ v3io_stream_consumer_group = [r"^(?!_)[a-zA-Z0-9_]{1,256}$"]
|
|
|
96
96
|
# URI patterns
|
|
97
97
|
run_uri_pattern = r"^(?P<project>.*)@(?P<uid>.*)\#(?P<iteration>.*?)(:(?P<tag>.*))?$"
|
|
98
98
|
|
|
99
|
-
artifact_uri_pattern =
|
|
99
|
+
artifact_uri_pattern = (
|
|
100
|
+
r"^((?P<project>.*)/)?" # Optional project
|
|
101
|
+
r"(?P<key>.*?)" # Key
|
|
102
|
+
r"(\#(?P<iteration>.*?))?" # Optional iteration
|
|
103
|
+
r"(:(?P<tag>.*?))?" # Optional tag
|
|
104
|
+
r"(@(?P<tree>.*?))?" # Optional tree
|
|
105
|
+
r"(\^(?P<uid>.*))?$" # Optional uid
|
|
106
|
+
)
|
|
100
107
|
|
|
101
108
|
artifact_producer_uri_pattern = (
|
|
102
109
|
r"^((?P<project>.*)/)?(?P<uid>.*?)(\-(?P<iteration>.*?))?$"
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mlrun
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.0rc9
|
|
4
4
|
Summary: Tracking and config of machine learning runs
|
|
5
5
|
Home-page: https://github.com/mlrun/mlrun
|
|
6
6
|
Author: Yaron Haviv
|
|
@@ -52,7 +52,7 @@ Requires-Dist: deprecated~=1.2
|
|
|
52
52
|
Requires-Dist: jinja2>=3.1.3,~=3.1
|
|
53
53
|
Requires-Dist: orjson<4,>=3.9.15
|
|
54
54
|
Requires-Dist: mlrun-pipelines-kfp-common~=0.2.3
|
|
55
|
-
Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.
|
|
55
|
+
Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.3; python_version < "3.11"
|
|
56
56
|
Requires-Dist: docstring_parser~=0.16
|
|
57
57
|
Requires-Dist: aiosmtplib~=3.0
|
|
58
58
|
Provides-Extra: s3
|