mlrun 1.7.1rc10__py3-none-any.whl → 1.8.0rc11__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 +23 -21
- mlrun/__main__.py +3 -3
- mlrun/alerts/alert.py +148 -14
- mlrun/artifacts/__init__.py +2 -3
- mlrun/artifacts/base.py +55 -12
- mlrun/artifacts/dataset.py +16 -16
- mlrun/artifacts/document.py +378 -0
- mlrun/artifacts/manager.py +26 -17
- mlrun/artifacts/model.py +66 -53
- mlrun/common/constants.py +8 -0
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/feature_set.py +1 -0
- mlrun/common/formatters/function.py +1 -0
- mlrun/{model_monitoring/db/stores/base/__init__.py → common/formatters/model_endpoint.py} +16 -1
- mlrun/common/formatters/pipeline.py +1 -2
- mlrun/common/formatters/project.py +9 -0
- mlrun/common/model_monitoring/__init__.py +0 -5
- mlrun/common/model_monitoring/helpers.py +1 -29
- mlrun/common/runtimes/constants.py +1 -2
- mlrun/common/schemas/__init__.py +6 -2
- mlrun/common/schemas/alert.py +111 -19
- mlrun/common/schemas/api_gateway.py +3 -3
- mlrun/common/schemas/artifact.py +11 -7
- mlrun/common/schemas/auth.py +6 -4
- mlrun/common/schemas/background_task.py +7 -7
- mlrun/common/schemas/client_spec.py +2 -3
- mlrun/common/schemas/clusterization_spec.py +2 -2
- mlrun/common/schemas/common.py +53 -3
- mlrun/common/schemas/constants.py +15 -0
- mlrun/common/schemas/datastore_profile.py +1 -1
- mlrun/common/schemas/feature_store.py +9 -9
- mlrun/common/schemas/frontend_spec.py +4 -4
- mlrun/common/schemas/function.py +10 -10
- mlrun/common/schemas/hub.py +1 -1
- mlrun/common/schemas/k8s.py +3 -3
- mlrun/common/schemas/memory_reports.py +3 -3
- mlrun/common/schemas/model_monitoring/__init__.py +2 -1
- mlrun/common/schemas/model_monitoring/constants.py +67 -14
- mlrun/common/schemas/model_monitoring/grafana.py +1 -1
- mlrun/common/schemas/model_monitoring/model_endpoints.py +92 -147
- mlrun/common/schemas/notification.py +24 -3
- mlrun/common/schemas/object.py +1 -1
- mlrun/common/schemas/pagination.py +4 -4
- mlrun/common/schemas/partition.py +137 -0
- mlrun/common/schemas/pipeline.py +2 -2
- mlrun/common/schemas/project.py +25 -17
- mlrun/common/schemas/runs.py +2 -2
- mlrun/common/schemas/runtime_resource.py +5 -5
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/secret.py +1 -1
- mlrun/common/schemas/tag.py +3 -3
- mlrun/common/schemas/workflow.py +5 -5
- mlrun/config.py +68 -10
- mlrun/data_types/__init__.py +0 -2
- mlrun/data_types/data_types.py +1 -0
- mlrun/data_types/infer.py +3 -1
- mlrun/data_types/spark.py +5 -3
- mlrun/data_types/to_pandas.py +11 -2
- mlrun/datastore/__init__.py +2 -2
- mlrun/datastore/alibaba_oss.py +4 -1
- mlrun/datastore/azure_blob.py +4 -1
- mlrun/datastore/base.py +12 -4
- mlrun/datastore/datastore.py +9 -3
- mlrun/datastore/datastore_profile.py +79 -20
- mlrun/datastore/dbfs_store.py +4 -1
- mlrun/datastore/filestore.py +4 -1
- mlrun/datastore/google_cloud_storage.py +4 -1
- mlrun/datastore/hdfs.py +4 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +4 -1
- mlrun/datastore/s3.py +4 -1
- mlrun/datastore/sources.py +52 -51
- mlrun/datastore/store_resources.py +7 -4
- mlrun/datastore/targets.py +23 -22
- mlrun/datastore/utils.py +2 -2
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/vectorstore.py +229 -0
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +213 -83
- mlrun/db/factory.py +0 -3
- mlrun/db/httpdb.py +1265 -387
- mlrun/db/nopdb.py +205 -74
- mlrun/errors.py +2 -2
- mlrun/execution.py +136 -50
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +41 -40
- mlrun/feature_store/common.py +9 -9
- mlrun/feature_store/feature_set.py +20 -18
- mlrun/feature_store/feature_vector.py +27 -24
- mlrun/feature_store/retrieval/base.py +14 -9
- mlrun/feature_store/retrieval/job.py +2 -1
- mlrun/feature_store/steps.py +2 -2
- mlrun/features.py +30 -13
- mlrun/frameworks/__init__.py +1 -2
- mlrun/frameworks/_common/__init__.py +1 -2
- mlrun/frameworks/_common/artifacts_library.py +2 -2
- mlrun/frameworks/_common/mlrun_interface.py +10 -6
- mlrun/frameworks/_common/model_handler.py +29 -27
- mlrun/frameworks/_common/producer.py +3 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
- mlrun/frameworks/_ml_common/__init__.py +1 -2
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_ml_common/model_handler.py +21 -21
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/auto_mlrun/__init__.py +1 -2
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
- mlrun/frameworks/huggingface/__init__.py +1 -2
- mlrun/frameworks/huggingface/model_server.py +9 -9
- mlrun/frameworks/lgbm/__init__.py +47 -44
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
- mlrun/frameworks/lgbm/model_handler.py +15 -11
- mlrun/frameworks/lgbm/model_server.py +11 -7
- mlrun/frameworks/lgbm/utils.py +2 -2
- mlrun/frameworks/onnx/__init__.py +1 -2
- mlrun/frameworks/onnx/dataset.py +3 -3
- mlrun/frameworks/onnx/mlrun_interface.py +2 -2
- mlrun/frameworks/onnx/model_handler.py +7 -5
- mlrun/frameworks/onnx/model_server.py +8 -6
- mlrun/frameworks/parallel_coordinates.py +11 -11
- mlrun/frameworks/pytorch/__init__.py +22 -23
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
- mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
- mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
- mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
- mlrun/frameworks/pytorch/model_handler.py +21 -17
- mlrun/frameworks/pytorch/model_server.py +13 -9
- mlrun/frameworks/sklearn/__init__.py +19 -18
- mlrun/frameworks/sklearn/estimator.py +2 -2
- mlrun/frameworks/sklearn/metric.py +3 -3
- mlrun/frameworks/sklearn/metrics_library.py +8 -6
- mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
- mlrun/frameworks/sklearn/model_handler.py +4 -3
- mlrun/frameworks/tf_keras/__init__.py +11 -12
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
- mlrun/frameworks/tf_keras/model_handler.py +17 -13
- mlrun/frameworks/tf_keras/model_server.py +12 -8
- mlrun/frameworks/xgboost/__init__.py +19 -18
- mlrun/frameworks/xgboost/model_handler.py +13 -9
- mlrun/launcher/base.py +3 -4
- mlrun/launcher/local.py +1 -1
- mlrun/launcher/remote.py +1 -1
- mlrun/lists.py +4 -3
- mlrun/model.py +117 -46
- mlrun/model_monitoring/__init__.py +4 -4
- mlrun/model_monitoring/api.py +72 -59
- mlrun/model_monitoring/applications/_application_steps.py +17 -17
- mlrun/model_monitoring/applications/base.py +165 -6
- mlrun/model_monitoring/applications/context.py +88 -37
- mlrun/model_monitoring/applications/evidently_base.py +0 -1
- mlrun/model_monitoring/applications/histogram_data_drift.py +43 -21
- mlrun/model_monitoring/applications/results.py +55 -3
- mlrun/model_monitoring/controller.py +207 -239
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/_schedules.py +156 -0
- mlrun/model_monitoring/db/_stats.py +189 -0
- mlrun/model_monitoring/db/tsdb/base.py +78 -25
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +61 -6
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +255 -29
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +78 -17
- mlrun/model_monitoring/helpers.py +151 -49
- mlrun/model_monitoring/stream_processing.py +99 -283
- mlrun/model_monitoring/tracking_policy.py +10 -3
- mlrun/model_monitoring/writer.py +48 -36
- mlrun/package/__init__.py +3 -6
- mlrun/package/context_handler.py +1 -1
- mlrun/package/packager.py +12 -9
- mlrun/package/packagers/__init__.py +0 -2
- mlrun/package/packagers/default_packager.py +14 -11
- mlrun/package/packagers/numpy_packagers.py +16 -7
- mlrun/package/packagers/pandas_packagers.py +18 -18
- mlrun/package/packagers/python_standard_library_packagers.py +25 -11
- mlrun/package/packagers_manager.py +31 -14
- mlrun/package/utils/__init__.py +0 -3
- mlrun/package/utils/_pickler.py +6 -6
- mlrun/platforms/__init__.py +47 -16
- mlrun/platforms/iguazio.py +4 -1
- mlrun/projects/operations.py +27 -27
- mlrun/projects/pipelines.py +71 -36
- mlrun/projects/project.py +890 -220
- mlrun/run.py +53 -10
- mlrun/runtimes/__init__.py +1 -3
- mlrun/runtimes/base.py +15 -11
- mlrun/runtimes/daskjob.py +9 -9
- mlrun/runtimes/generators.py +2 -1
- mlrun/runtimes/kubejob.py +4 -5
- mlrun/runtimes/mounts.py +572 -0
- mlrun/runtimes/mpijob/__init__.py +0 -2
- mlrun/runtimes/mpijob/abstract.py +7 -6
- mlrun/runtimes/nuclio/api_gateway.py +7 -7
- mlrun/runtimes/nuclio/application/application.py +11 -11
- mlrun/runtimes/nuclio/function.py +19 -17
- mlrun/runtimes/nuclio/serving.py +18 -13
- mlrun/runtimes/pod.py +154 -45
- mlrun/runtimes/remotesparkjob.py +3 -2
- mlrun/runtimes/sparkjob/__init__.py +0 -2
- mlrun/runtimes/sparkjob/spark3job.py +21 -11
- mlrun/runtimes/utils.py +6 -5
- mlrun/serving/merger.py +6 -4
- mlrun/serving/remote.py +18 -17
- mlrun/serving/routers.py +185 -172
- mlrun/serving/server.py +7 -1
- mlrun/serving/states.py +97 -78
- mlrun/serving/utils.py +13 -2
- mlrun/serving/v1_serving.py +3 -2
- mlrun/serving/v2_serving.py +105 -72
- mlrun/track/__init__.py +1 -1
- mlrun/track/tracker.py +2 -2
- mlrun/track/trackers/mlflow_tracker.py +6 -5
- mlrun/utils/async_http.py +1 -1
- mlrun/utils/clones.py +1 -1
- mlrun/utils/helpers.py +63 -19
- mlrun/utils/logger.py +106 -4
- mlrun/utils/notifications/notification/__init__.py +22 -19
- mlrun/utils/notifications/notification/base.py +33 -14
- mlrun/utils/notifications/notification/console.py +6 -6
- mlrun/utils/notifications/notification/git.py +11 -11
- mlrun/utils/notifications/notification/ipython.py +10 -9
- mlrun/utils/notifications/notification/mail.py +176 -0
- mlrun/utils/notifications/notification/slack.py +6 -6
- mlrun/utils/notifications/notification/webhook.py +6 -6
- mlrun/utils/notifications/notification_pusher.py +86 -44
- mlrun/utils/regex.py +11 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.1rc10.dist-info → mlrun-1.8.0rc11.dist-info}/METADATA +29 -24
- mlrun-1.8.0rc11.dist-info/RECORD +347 -0
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/store.py +0 -213
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -71
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -190
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -103
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -40
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -659
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -726
- mlrun/model_monitoring/model_endpoint.py +0 -118
- mlrun-1.7.1rc10.dist-info/RECORD +0 -351
- {mlrun-1.7.1rc10.dist-info → mlrun-1.8.0rc11.dist-info}/LICENSE +0 -0
- {mlrun-1.7.1rc10.dist-info → mlrun-1.8.0rc11.dist-info}/WHEEL +0 -0
- {mlrun-1.7.1rc10.dist-info → mlrun-1.8.0rc11.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.1rc10.dist-info → mlrun-1.8.0rc11.dist-info}/top_level.txt +0 -0
|
@@ -15,6 +15,7 @@ import os
|
|
|
15
15
|
import pathlib
|
|
16
16
|
import tempfile
|
|
17
17
|
import zipfile
|
|
18
|
+
from typing import Optional
|
|
18
19
|
|
|
19
20
|
import mlflow
|
|
20
21
|
import mlflow.entities
|
|
@@ -190,7 +191,7 @@ class MLFlowTracker(Tracker):
|
|
|
190
191
|
project: MlrunProject,
|
|
191
192
|
reference_id: str,
|
|
192
193
|
function_name: str,
|
|
193
|
-
handler: str = None,
|
|
194
|
+
handler: Optional[str] = None,
|
|
194
195
|
**kwargs,
|
|
195
196
|
) -> RunObject:
|
|
196
197
|
"""
|
|
@@ -251,9 +252,9 @@ class MLFlowTracker(Tracker):
|
|
|
251
252
|
self,
|
|
252
253
|
project: MlrunProject,
|
|
253
254
|
reference_id: str,
|
|
254
|
-
key: str = None,
|
|
255
|
-
metrics: dict = None,
|
|
256
|
-
extra_data: dict = None,
|
|
255
|
+
key: Optional[str] = None,
|
|
256
|
+
metrics: Optional[dict] = None,
|
|
257
|
+
extra_data: Optional[dict] = None,
|
|
257
258
|
) -> ModelArtifact:
|
|
258
259
|
"""
|
|
259
260
|
Import a model from MLFlow to MLRun.
|
|
@@ -290,7 +291,7 @@ class MLFlowTracker(Tracker):
|
|
|
290
291
|
return model
|
|
291
292
|
|
|
292
293
|
def import_artifact(
|
|
293
|
-
self, project: MlrunProject, reference_id: str, key: str = None
|
|
294
|
+
self, project: MlrunProject, reference_id: str, key: Optional[str] = None
|
|
294
295
|
) -> Artifact:
|
|
295
296
|
"""
|
|
296
297
|
Import an artifact from MLFlow to MLRun.
|
mlrun/utils/async_http.py
CHANGED
|
@@ -42,7 +42,7 @@ class AsyncClientWithRetry(RetryClient):
|
|
|
42
42
|
retry_on_exception: bool = True,
|
|
43
43
|
raise_for_status: bool = True,
|
|
44
44
|
blacklisted_methods: typing.Optional[list[str]] = None,
|
|
45
|
-
logger: logging.Logger = None,
|
|
45
|
+
logger: Optional[logging.Logger] = None,
|
|
46
46
|
*args,
|
|
47
47
|
**kwargs,
|
|
48
48
|
):
|
mlrun/utils/clones.py
CHANGED
|
@@ -122,7 +122,7 @@ def add_credentials_git_remote_url(url: str, secrets=None) -> tuple[str, bool]:
|
|
|
122
122
|
username, password = get_git_username_password_from_token(token)
|
|
123
123
|
|
|
124
124
|
if username:
|
|
125
|
-
return f"https://{username}:{password}@{url_obj.
|
|
125
|
+
return f"https://{username}:{password}@{url_obj.netloc}{url_obj.path}", True
|
|
126
126
|
return url, False
|
|
127
127
|
|
|
128
128
|
|
mlrun/utils/helpers.py
CHANGED
|
@@ -40,7 +40,6 @@ import pandas
|
|
|
40
40
|
import semver
|
|
41
41
|
import yaml
|
|
42
42
|
from dateutil import parser
|
|
43
|
-
from mlrun_pipelines.models import PipelineRun
|
|
44
43
|
from pandas import Timedelta, Timestamp
|
|
45
44
|
from yaml.representer import RepresenterError
|
|
46
45
|
|
|
@@ -52,6 +51,7 @@ import mlrun.utils.regex
|
|
|
52
51
|
import mlrun.utils.version.version
|
|
53
52
|
from mlrun.common.constants import MYSQL_MEDIUMBLOB_SIZE_BYTES
|
|
54
53
|
from mlrun.config import config
|
|
54
|
+
from mlrun_pipelines.models import PipelineRun
|
|
55
55
|
|
|
56
56
|
from .logger import create_logger
|
|
57
57
|
from .retryer import ( # noqa: F401
|
|
@@ -167,6 +167,7 @@ class RunKeys:
|
|
|
167
167
|
inputs = "inputs"
|
|
168
168
|
returns = "returns"
|
|
169
169
|
artifacts = "artifacts"
|
|
170
|
+
artifact_uris = "artifact_uris"
|
|
170
171
|
outputs = "outputs"
|
|
171
172
|
data_stores = "data_stores"
|
|
172
173
|
secrets = "secret_sources"
|
|
@@ -220,7 +221,7 @@ def verify_field_regex(
|
|
|
220
221
|
|
|
221
222
|
|
|
222
223
|
def validate_builder_source(
|
|
223
|
-
source: str, pull_at_runtime: bool = False, workdir: str = None
|
|
224
|
+
source: str, pull_at_runtime: bool = False, workdir: Optional[str] = None
|
|
224
225
|
):
|
|
225
226
|
if pull_at_runtime or not source:
|
|
226
227
|
return
|
|
@@ -268,12 +269,14 @@ def validate_tag_name(
|
|
|
268
269
|
def validate_artifact_key_name(
|
|
269
270
|
artifact_key: str, field_name: str, raise_on_failure: bool = True
|
|
270
271
|
) -> bool:
|
|
272
|
+
field_type = "key" if field_name == "artifact.key" else "db_key"
|
|
271
273
|
return mlrun.utils.helpers.verify_field_regex(
|
|
272
274
|
field_name,
|
|
273
275
|
artifact_key,
|
|
274
276
|
mlrun.utils.regex.artifact_key,
|
|
275
277
|
raise_on_failure=raise_on_failure,
|
|
276
|
-
log_message="
|
|
278
|
+
log_message=f"Artifact {field_type} must start and end with an alphanumeric character, and may only contain "
|
|
279
|
+
"letters, numbers, hyphens, underscores, and dots.",
|
|
277
280
|
)
|
|
278
281
|
|
|
279
282
|
|
|
@@ -354,8 +357,8 @@ def verify_field_list_of_type(
|
|
|
354
357
|
def verify_dict_items_type(
|
|
355
358
|
name: str,
|
|
356
359
|
dictionary: dict,
|
|
357
|
-
expected_keys_types: list = None,
|
|
358
|
-
expected_values_types: list = None,
|
|
360
|
+
expected_keys_types: Optional[list] = None,
|
|
361
|
+
expected_values_types: Optional[list] = None,
|
|
359
362
|
):
|
|
360
363
|
if dictionary:
|
|
361
364
|
if not isinstance(dictionary, dict):
|
|
@@ -372,7 +375,7 @@ def verify_dict_items_type(
|
|
|
372
375
|
) from exc
|
|
373
376
|
|
|
374
377
|
|
|
375
|
-
def verify_list_items_type(list_, expected_types: list = None):
|
|
378
|
+
def verify_list_items_type(list_, expected_types: Optional[list] = None):
|
|
376
379
|
if list_ and expected_types:
|
|
377
380
|
list_items_types = set(map(type, list_))
|
|
378
381
|
expected_types = set(expected_types)
|
|
@@ -396,6 +399,10 @@ def now_date(tz: timezone = timezone.utc) -> datetime:
|
|
|
396
399
|
return datetime.now(tz=tz)
|
|
397
400
|
|
|
398
401
|
|
|
402
|
+
def datetime_min(tz: timezone = timezone.utc) -> datetime:
|
|
403
|
+
return datetime(1970, 1, 1, tzinfo=tz)
|
|
404
|
+
|
|
405
|
+
|
|
399
406
|
datetime_now = now_date
|
|
400
407
|
|
|
401
408
|
|
|
@@ -663,8 +670,8 @@ def dict_to_json(struct):
|
|
|
663
670
|
|
|
664
671
|
def parse_artifact_uri(uri, default_project=""):
|
|
665
672
|
"""
|
|
666
|
-
Parse artifact URI into project, key, tag, iter, tree
|
|
667
|
-
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>]
|
|
668
675
|
|
|
669
676
|
:param uri: uri to parse
|
|
670
677
|
:param default_project: default project name if not in URI
|
|
@@ -674,6 +681,7 @@ def parse_artifact_uri(uri, default_project=""):
|
|
|
674
681
|
[2] = iteration
|
|
675
682
|
[3] = tag
|
|
676
683
|
[4] = tree
|
|
684
|
+
[5] = uid
|
|
677
685
|
"""
|
|
678
686
|
uri_pattern = mlrun.utils.regex.artifact_uri_pattern
|
|
679
687
|
match = re.match(uri_pattern, uri)
|
|
@@ -698,6 +706,7 @@ def parse_artifact_uri(uri, default_project=""):
|
|
|
698
706
|
iteration,
|
|
699
707
|
group_dict["tag"],
|
|
700
708
|
group_dict["tree"],
|
|
709
|
+
group_dict["uid"],
|
|
701
710
|
)
|
|
702
711
|
|
|
703
712
|
|
|
@@ -712,7 +721,9 @@ def generate_object_uri(project, name, tag=None, hash_key=None):
|
|
|
712
721
|
return uri
|
|
713
722
|
|
|
714
723
|
|
|
715
|
-
def generate_artifact_uri(
|
|
724
|
+
def generate_artifact_uri(
|
|
725
|
+
project, key, tag=None, iter=None, tree=None, uid=None
|
|
726
|
+
) -> str:
|
|
716
727
|
artifact_uri = f"{project}/{key}"
|
|
717
728
|
if iter is not None:
|
|
718
729
|
artifact_uri = f"{artifact_uri}#{iter}"
|
|
@@ -720,6 +731,8 @@ def generate_artifact_uri(project, key, tag=None, iter=None, tree=None):
|
|
|
720
731
|
artifact_uri = f"{artifact_uri}:{tag}"
|
|
721
732
|
if tree is not None:
|
|
722
733
|
artifact_uri = f"{artifact_uri}@{tree}"
|
|
734
|
+
if uid is not None:
|
|
735
|
+
artifact_uri = f"{artifact_uri}^{uid}"
|
|
723
736
|
return artifact_uri
|
|
724
737
|
|
|
725
738
|
|
|
@@ -816,7 +829,9 @@ def _convert_python_package_version_to_image_tag(version: typing.Optional[str]):
|
|
|
816
829
|
|
|
817
830
|
|
|
818
831
|
def enrich_image_url(
|
|
819
|
-
image_url: str,
|
|
832
|
+
image_url: str,
|
|
833
|
+
client_version: Optional[str] = None,
|
|
834
|
+
client_python_version: Optional[str] = None,
|
|
820
835
|
) -> str:
|
|
821
836
|
client_version = _convert_python_package_version_to_image_tag(client_version)
|
|
822
837
|
server_version = _convert_python_package_version_to_image_tag(
|
|
@@ -856,7 +871,7 @@ def enrich_image_url(
|
|
|
856
871
|
|
|
857
872
|
|
|
858
873
|
def resolve_image_tag_suffix(
|
|
859
|
-
mlrun_version: str = None, python_version: str = None
|
|
874
|
+
mlrun_version: Optional[str] = None, python_version: Optional[str] = None
|
|
860
875
|
) -> str:
|
|
861
876
|
"""
|
|
862
877
|
resolves what suffix should be appended to the image tag
|
|
@@ -1175,7 +1190,7 @@ def get_function(function, namespaces, reload_modules: bool = False):
|
|
|
1175
1190
|
def get_handler_extended(
|
|
1176
1191
|
handler_path: str,
|
|
1177
1192
|
context=None,
|
|
1178
|
-
class_args: dict = None,
|
|
1193
|
+
class_args: Optional[dict] = None,
|
|
1179
1194
|
namespaces=None,
|
|
1180
1195
|
reload_modules: bool = False,
|
|
1181
1196
|
):
|
|
@@ -1694,17 +1709,22 @@ def merge_dicts_with_precedence(*dicts: dict) -> dict:
|
|
|
1694
1709
|
|
|
1695
1710
|
|
|
1696
1711
|
def validate_component_version_compatibility(
|
|
1697
|
-
component_name: typing.Literal["iguazio", "nuclio"],
|
|
1712
|
+
component_name: typing.Literal["iguazio", "nuclio", "mlrun-client"],
|
|
1713
|
+
*min_versions: str,
|
|
1714
|
+
mlrun_client_version: Optional[str] = None,
|
|
1698
1715
|
):
|
|
1699
1716
|
"""
|
|
1700
1717
|
:param component_name: Name of the component to validate compatibility for.
|
|
1701
1718
|
:param min_versions: Valid minimum version(s) required, assuming no 2 versions has equal major and minor.
|
|
1719
|
+
:param mlrun_client_version: Client version to validate when component_name is "mlrun-client".
|
|
1702
1720
|
"""
|
|
1703
1721
|
parsed_min_versions = [
|
|
1704
1722
|
semver.VersionInfo.parse(min_version) for min_version in min_versions
|
|
1705
1723
|
]
|
|
1706
1724
|
parsed_current_version = None
|
|
1707
1725
|
component_current_version = None
|
|
1726
|
+
# For mlrun client we don't assume compatability if we fail to parse the client version
|
|
1727
|
+
assume_compatible = component_name not in ["mlrun-client"]
|
|
1708
1728
|
try:
|
|
1709
1729
|
if component_name == "iguazio":
|
|
1710
1730
|
component_current_version = mlrun.mlconf.igz_version
|
|
@@ -1721,18 +1741,29 @@ def validate_component_version_compatibility(
|
|
|
1721
1741
|
parsed_current_version = semver.VersionInfo.parse(
|
|
1722
1742
|
mlrun.mlconf.nuclio_version
|
|
1723
1743
|
)
|
|
1744
|
+
if component_name == "mlrun-client":
|
|
1745
|
+
# dev version, assume compatible
|
|
1746
|
+
if mlrun_client_version and (
|
|
1747
|
+
mlrun_client_version.startswith("0.0.0+")
|
|
1748
|
+
or "unstable" in mlrun_client_version
|
|
1749
|
+
):
|
|
1750
|
+
return True
|
|
1751
|
+
|
|
1752
|
+
component_current_version = mlrun_client_version
|
|
1753
|
+
parsed_current_version = semver.Version.parse(mlrun_client_version)
|
|
1724
1754
|
if not parsed_current_version:
|
|
1725
|
-
return
|
|
1755
|
+
return assume_compatible
|
|
1726
1756
|
except ValueError:
|
|
1727
1757
|
# only log when version is set but invalid
|
|
1728
1758
|
if component_current_version:
|
|
1729
1759
|
logger.warning(
|
|
1730
|
-
"Unable to parse current version
|
|
1760
|
+
"Unable to parse current version",
|
|
1731
1761
|
component_name=component_name,
|
|
1732
1762
|
current_version=component_current_version,
|
|
1733
1763
|
min_versions=min_versions,
|
|
1764
|
+
assume_compatible=assume_compatible,
|
|
1734
1765
|
)
|
|
1735
|
-
return
|
|
1766
|
+
return assume_compatible
|
|
1736
1767
|
|
|
1737
1768
|
# Feature might have been back-ported e.g. nuclio node selection is supported from
|
|
1738
1769
|
# 1.5.20 and 1.6.10 but not in 1.6.9 - therefore we reverse sort to validate against 1.6.x 1st and
|
|
@@ -1797,9 +1828,8 @@ def _reload(module, max_recursion_depth):
|
|
|
1797
1828
|
def run_with_retry(
|
|
1798
1829
|
retry_count: int,
|
|
1799
1830
|
func: typing.Callable,
|
|
1800
|
-
retry_on_exceptions:
|
|
1801
|
-
type[Exception],
|
|
1802
|
-
tuple[type[Exception]],
|
|
1831
|
+
retry_on_exceptions: Optional[
|
|
1832
|
+
typing.Union[type[Exception], tuple[type[Exception]]]
|
|
1803
1833
|
] = None,
|
|
1804
1834
|
*args,
|
|
1805
1835
|
**kwargs,
|
|
@@ -1832,3 +1862,17 @@ def run_with_retry(
|
|
|
1832
1862
|
if attempt == retry_count:
|
|
1833
1863
|
raise
|
|
1834
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
|
mlrun/utils/logger.py
CHANGED
|
@@ -11,9 +11,11 @@
|
|
|
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
|
-
|
|
14
|
+
import datetime
|
|
15
15
|
import logging
|
|
16
16
|
import os
|
|
17
|
+
import string
|
|
18
|
+
import sys
|
|
17
19
|
import typing
|
|
18
20
|
from enum import Enum
|
|
19
21
|
from functools import cached_property
|
|
@@ -22,15 +24,16 @@ from traceback import format_exception
|
|
|
22
24
|
from typing import IO, Optional, Union
|
|
23
25
|
|
|
24
26
|
import orjson
|
|
25
|
-
import pydantic
|
|
27
|
+
import pydantic.v1
|
|
26
28
|
|
|
29
|
+
from mlrun import errors
|
|
27
30
|
from mlrun.config import config
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
class _BaseFormatter(logging.Formatter):
|
|
31
34
|
def _json_dump(self, json_object):
|
|
32
35
|
def default(obj):
|
|
33
|
-
if isinstance(obj, pydantic.BaseModel):
|
|
36
|
+
if isinstance(obj, pydantic.v1.BaseModel):
|
|
34
37
|
return obj.dict()
|
|
35
38
|
|
|
36
39
|
# EAFP all the way.
|
|
@@ -93,6 +96,98 @@ class HumanReadableFormatter(_BaseFormatter):
|
|
|
93
96
|
return record_with
|
|
94
97
|
|
|
95
98
|
|
|
99
|
+
class CustomFormatter(HumanReadableFormatter):
|
|
100
|
+
"""
|
|
101
|
+
To enable custom logger formatter, configure MLRun with the following env variables:
|
|
102
|
+
1. "MLRUN_LOG_FORMATTER" = "custom" - change the default log formatter.
|
|
103
|
+
2. "MLRUN_LOG_FORMAT_OVERRIDE" = "> {timestamp} [{level}] Running module: {module} {message} {more}" - logger format
|
|
104
|
+
* Note that your custom format must include those 4 fields - timestamp, level, message and more
|
|
105
|
+
If the custom format is not configured properly , MLRun will use the default logger (human format).
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
# This attribute is used to solve an issue
|
|
109
|
+
# that causes the warning to be written numerous times(for any log generation).
|
|
110
|
+
# We want to print the errors just once, not for each logger generation.
|
|
111
|
+
fail_on_format_configuration = False # for issues that relates to unrecognized keys
|
|
112
|
+
fail_on_missing_default_keys_key = (
|
|
113
|
+
False # for issues that relates to missing default keys
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def format(self, record) -> str:
|
|
117
|
+
more = self._resolve_more(record)
|
|
118
|
+
custom_format = config.log_format_override
|
|
119
|
+
_custom_format = None
|
|
120
|
+
current_time = datetime.datetime.now()
|
|
121
|
+
formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S,%f")[:-3]
|
|
122
|
+
try:
|
|
123
|
+
if custom_format:
|
|
124
|
+
default_keys = ["timestamp", "level", "message", "more"]
|
|
125
|
+
formatter = string.Formatter()
|
|
126
|
+
custom_format_keys = [
|
|
127
|
+
key
|
|
128
|
+
for _, key, _, _ in formatter.parse(custom_format)
|
|
129
|
+
if key is not None
|
|
130
|
+
]
|
|
131
|
+
missing_default_flags = list(
|
|
132
|
+
set(default_keys) - set(custom_format_keys)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if (
|
|
136
|
+
missing_default_flags
|
|
137
|
+
and not CustomFormatter.fail_on_missing_default_keys_key
|
|
138
|
+
):
|
|
139
|
+
print(
|
|
140
|
+
f'> {formatted_time} [warning] Custom loggers must '
|
|
141
|
+
f'include those keys within the logger format, {", ".join(default_keys)} '
|
|
142
|
+
f'your format is missing: {", ".join(missing_default_flags)}',
|
|
143
|
+
file=sys.stderr,
|
|
144
|
+
)
|
|
145
|
+
CustomFormatter.fail_on_missing_default_keys_key = True
|
|
146
|
+
record_dict = record.__dict__
|
|
147
|
+
missing_format_configuraiton_keys = list(
|
|
148
|
+
set(custom_format_keys)
|
|
149
|
+
- set(default_keys)
|
|
150
|
+
- set(record_dict.keys())
|
|
151
|
+
)
|
|
152
|
+
if missing_format_configuraiton_keys:
|
|
153
|
+
if not CustomFormatter.fail_on_format_configuration:
|
|
154
|
+
print(
|
|
155
|
+
f"> {formatted_time} [warning] Failed to create custom logger due "
|
|
156
|
+
f'to missing format key in the log record: {", ".join(missing_format_configuraiton_keys)}',
|
|
157
|
+
file=sys.stderr,
|
|
158
|
+
)
|
|
159
|
+
CustomFormatter.fail_on_format_configuration = True
|
|
160
|
+
_format = (
|
|
161
|
+
f"> {self.formatTime(record, self.datefmt)} "
|
|
162
|
+
f"[{record.levelname.lower()}] "
|
|
163
|
+
f"{record.getMessage().rstrip()}"
|
|
164
|
+
f"{more}"
|
|
165
|
+
)
|
|
166
|
+
_custom_format = custom_format.format(
|
|
167
|
+
timestamp=self.formatTime(record, self.datefmt),
|
|
168
|
+
level=record.levelname.lower(),
|
|
169
|
+
message=record.getMessage().rstrip(),
|
|
170
|
+
more=more or "",
|
|
171
|
+
**record_dict,
|
|
172
|
+
)
|
|
173
|
+
CustomFormatter.fail_on_format_configuration = True
|
|
174
|
+
except Exception as e:
|
|
175
|
+
if not CustomFormatter.fail_on_format_configuration:
|
|
176
|
+
print(
|
|
177
|
+
f"> {formatted_time} [warning] Failed to create custom logger, "
|
|
178
|
+
f"see Exception: {errors.err_to_str(e)}",
|
|
179
|
+
file=sys.stderr,
|
|
180
|
+
)
|
|
181
|
+
CustomFormatter.fail_on_format_configuration = True
|
|
182
|
+
_format = _custom_format or (
|
|
183
|
+
f"> {self.formatTime(record, self.datefmt)} "
|
|
184
|
+
f"[{record.levelname.lower()}] "
|
|
185
|
+
f"{record.getMessage().rstrip()}"
|
|
186
|
+
f"{more}"
|
|
187
|
+
)
|
|
188
|
+
return _format
|
|
189
|
+
|
|
190
|
+
|
|
96
191
|
class HumanReadableExtendedFormatter(HumanReadableFormatter):
|
|
97
192
|
_colors = {
|
|
98
193
|
logging.NOTSET: "",
|
|
@@ -272,17 +367,24 @@ class FormatterKinds(Enum):
|
|
|
272
367
|
HUMAN = "human"
|
|
273
368
|
HUMAN_EXTENDED = "human_extended"
|
|
274
369
|
JSON = "json"
|
|
370
|
+
CUSTOM = "custom"
|
|
275
371
|
|
|
276
372
|
|
|
277
373
|
def resolve_formatter_by_kind(
|
|
278
374
|
formatter_kind: FormatterKinds,
|
|
279
375
|
) -> type[
|
|
280
|
-
typing.Union[
|
|
376
|
+
typing.Union[
|
|
377
|
+
HumanReadableFormatter,
|
|
378
|
+
HumanReadableExtendedFormatter,
|
|
379
|
+
JSONFormatter,
|
|
380
|
+
CustomFormatter,
|
|
381
|
+
]
|
|
281
382
|
]:
|
|
282
383
|
return {
|
|
283
384
|
FormatterKinds.HUMAN: HumanReadableFormatter,
|
|
284
385
|
FormatterKinds.HUMAN_EXTENDED: HumanReadableExtendedFormatter,
|
|
285
386
|
FormatterKinds.JSON: JSONFormatter,
|
|
387
|
+
FormatterKinds.CUSTOM: CustomFormatter,
|
|
286
388
|
}[formatter_kind]
|
|
287
389
|
|
|
288
390
|
|
|
@@ -14,30 +14,32 @@
|
|
|
14
14
|
|
|
15
15
|
import enum
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
import mlrun.common.schemas.notification as notifications
|
|
18
|
+
import mlrun.utils.notifications.notification.base as base
|
|
19
|
+
import mlrun.utils.notifications.notification.console as console
|
|
20
|
+
import mlrun.utils.notifications.notification.git as git
|
|
21
|
+
import mlrun.utils.notifications.notification.ipython as ipython
|
|
22
|
+
import mlrun.utils.notifications.notification.mail as mail
|
|
23
|
+
import mlrun.utils.notifications.notification.slack as slack
|
|
24
|
+
import mlrun.utils.notifications.notification.webhook as webhook
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class NotificationTypes(str, enum.Enum):
|
|
28
|
-
console = NotificationKind.console.value
|
|
29
|
-
git = NotificationKind.git.value
|
|
30
|
-
ipython = NotificationKind.ipython.value
|
|
31
|
-
slack = NotificationKind.slack.value
|
|
32
|
-
|
|
28
|
+
console = notifications.NotificationKind.console.value
|
|
29
|
+
git = notifications.NotificationKind.git.value
|
|
30
|
+
ipython = notifications.NotificationKind.ipython.value
|
|
31
|
+
slack = notifications.NotificationKind.slack.value
|
|
32
|
+
mail = notifications.NotificationKind.mail.value
|
|
33
|
+
webhook = notifications.NotificationKind.webhook.value
|
|
33
34
|
|
|
34
|
-
def get_notification(self) -> type[NotificationBase]:
|
|
35
|
+
def get_notification(self) -> type[base.NotificationBase]:
|
|
35
36
|
return {
|
|
36
|
-
self.console: ConsoleNotification,
|
|
37
|
-
self.git: GitNotification,
|
|
38
|
-
self.ipython: IPythonNotification,
|
|
39
|
-
self.slack: SlackNotification,
|
|
40
|
-
self.
|
|
37
|
+
self.console: console.ConsoleNotification,
|
|
38
|
+
self.git: git.GitNotification,
|
|
39
|
+
self.ipython: ipython.IPythonNotification,
|
|
40
|
+
self.slack: slack.SlackNotification,
|
|
41
|
+
self.mail: mail.MailNotification,
|
|
42
|
+
self.webhook: webhook.WebhookNotification,
|
|
41
43
|
}.get(self)
|
|
42
44
|
|
|
43
45
|
def inverse_dependencies(self) -> list[str]:
|
|
@@ -64,5 +66,6 @@ class NotificationTypes(str, enum.Enum):
|
|
|
64
66
|
cls.git,
|
|
65
67
|
cls.ipython,
|
|
66
68
|
cls.slack,
|
|
69
|
+
cls.mail,
|
|
67
70
|
cls.webhook,
|
|
68
71
|
]
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import asyncio
|
|
16
16
|
import typing
|
|
17
|
+
from copy import deepcopy
|
|
17
18
|
|
|
18
19
|
import mlrun.common.schemas
|
|
19
20
|
import mlrun.lists
|
|
@@ -22,11 +23,20 @@ import mlrun.lists
|
|
|
22
23
|
class NotificationBase:
|
|
23
24
|
def __init__(
|
|
24
25
|
self,
|
|
25
|
-
name: str = None,
|
|
26
|
-
params: dict[str, str] = None,
|
|
26
|
+
name: typing.Optional[str] = None,
|
|
27
|
+
params: typing.Optional[dict[str, str]] = None,
|
|
28
|
+
default_params: typing.Optional[dict[str, str]] = None,
|
|
27
29
|
):
|
|
30
|
+
"""
|
|
31
|
+
NotificationBase is the base class for all notification types.
|
|
32
|
+
|
|
33
|
+
:param name: The name of the notification.
|
|
34
|
+
:param params: The parameters of the notification.
|
|
35
|
+
:param default_params: The default parameters of the notification. Used for server-side enrichment purposes.
|
|
36
|
+
"""
|
|
28
37
|
self.name = name
|
|
29
38
|
self.params = params or {}
|
|
39
|
+
self.params = self.enrich_default_params(self.params, default_params)
|
|
30
40
|
|
|
31
41
|
@classmethod
|
|
32
42
|
def validate_params(cls, params):
|
|
@@ -43,13 +53,13 @@ class NotificationBase:
|
|
|
43
53
|
def push(
|
|
44
54
|
self,
|
|
45
55
|
message: str,
|
|
46
|
-
severity: typing.
|
|
47
|
-
mlrun.common.schemas.NotificationSeverity, str
|
|
56
|
+
severity: typing.Optional[
|
|
57
|
+
typing.Union[mlrun.common.schemas.NotificationSeverity, str]
|
|
48
58
|
] = mlrun.common.schemas.NotificationSeverity.INFO,
|
|
49
|
-
runs: typing.Union[mlrun.lists.RunList, list] = None,
|
|
50
|
-
custom_html: str = None,
|
|
51
|
-
alert: mlrun.common.schemas.AlertConfig = None,
|
|
52
|
-
event_data: mlrun.common.schemas.Event = None,
|
|
59
|
+
runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
|
|
60
|
+
custom_html: typing.Optional[typing.Optional[str]] = None,
|
|
61
|
+
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
62
|
+
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
53
63
|
):
|
|
54
64
|
raise NotImplementedError()
|
|
55
65
|
|
|
@@ -59,16 +69,25 @@ class NotificationBase:
|
|
|
59
69
|
) -> None:
|
|
60
70
|
self.params = params or {}
|
|
61
71
|
|
|
72
|
+
@classmethod
|
|
73
|
+
def enrich_default_params(
|
|
74
|
+
cls, params: dict, default_params: typing.Optional[dict] = None
|
|
75
|
+
) -> dict:
|
|
76
|
+
default_params = default_params or {}
|
|
77
|
+
returned_params = deepcopy(default_params)
|
|
78
|
+
returned_params.update(params)
|
|
79
|
+
return returned_params
|
|
80
|
+
|
|
62
81
|
def _get_html(
|
|
63
82
|
self,
|
|
64
83
|
message: str,
|
|
65
|
-
severity: typing.
|
|
66
|
-
mlrun.common.schemas.NotificationSeverity, str
|
|
84
|
+
severity: typing.Optional[
|
|
85
|
+
typing.Union[mlrun.common.schemas.NotificationSeverity, str]
|
|
67
86
|
] = mlrun.common.schemas.NotificationSeverity.INFO,
|
|
68
|
-
runs: typing.Union[mlrun.lists.RunList, list] = None,
|
|
69
|
-
custom_html: str = None,
|
|
70
|
-
alert: mlrun.common.schemas.AlertConfig = None,
|
|
71
|
-
event_data: mlrun.common.schemas.Event = None,
|
|
87
|
+
runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
|
|
88
|
+
custom_html: typing.Optional[typing.Optional[str]] = None,
|
|
89
|
+
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
90
|
+
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
72
91
|
) -> str:
|
|
73
92
|
if custom_html:
|
|
74
93
|
return custom_html
|
|
@@ -31,13 +31,13 @@ class ConsoleNotification(NotificationBase):
|
|
|
31
31
|
def push(
|
|
32
32
|
self,
|
|
33
33
|
message: str,
|
|
34
|
-
severity: typing.
|
|
35
|
-
mlrun.common.schemas.NotificationSeverity, str
|
|
34
|
+
severity: typing.Optional[
|
|
35
|
+
typing.Union[mlrun.common.schemas.NotificationSeverity, str]
|
|
36
36
|
] = mlrun.common.schemas.NotificationSeverity.INFO,
|
|
37
|
-
runs: typing.Union[mlrun.lists.RunList, list] = None,
|
|
38
|
-
custom_html: str = None,
|
|
39
|
-
alert: mlrun.common.schemas.AlertConfig = None,
|
|
40
|
-
event_data: mlrun.common.schemas.Event = None,
|
|
37
|
+
runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
|
|
38
|
+
custom_html: typing.Optional[typing.Optional[str]] = None,
|
|
39
|
+
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
40
|
+
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
41
41
|
):
|
|
42
42
|
severity = self._resolve_severity(severity)
|
|
43
43
|
print(f"[{severity}] {message}")
|
|
@@ -54,13 +54,13 @@ class GitNotification(NotificationBase):
|
|
|
54
54
|
async def push(
|
|
55
55
|
self,
|
|
56
56
|
message: str,
|
|
57
|
-
severity: typing.
|
|
58
|
-
mlrun.common.schemas.NotificationSeverity, str
|
|
57
|
+
severity: typing.Optional[
|
|
58
|
+
typing.Union[mlrun.common.schemas.NotificationSeverity, str]
|
|
59
59
|
] = mlrun.common.schemas.NotificationSeverity.INFO,
|
|
60
|
-
runs: typing.Union[mlrun.lists.RunList, list] = None,
|
|
61
|
-
custom_html: str = None,
|
|
62
|
-
alert: mlrun.common.schemas.AlertConfig = None,
|
|
63
|
-
event_data: mlrun.common.schemas.Event = None,
|
|
60
|
+
runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
|
|
61
|
+
custom_html: typing.Optional[typing.Optional[str]] = None,
|
|
62
|
+
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
63
|
+
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
64
64
|
):
|
|
65
65
|
git_repo = self.params.get("repo", None)
|
|
66
66
|
git_issue = self.params.get("issue", None)
|
|
@@ -85,11 +85,11 @@ class GitNotification(NotificationBase):
|
|
|
85
85
|
@staticmethod
|
|
86
86
|
async def _pr_comment(
|
|
87
87
|
message: str,
|
|
88
|
-
repo: str = None,
|
|
89
|
-
issue: int = None,
|
|
90
|
-
merge_request: int = None,
|
|
91
|
-
token: str = None,
|
|
92
|
-
server: str = None,
|
|
88
|
+
repo: typing.Optional[str] = None,
|
|
89
|
+
issue: typing.Optional[int] = None,
|
|
90
|
+
merge_request: typing.Optional[int] = None,
|
|
91
|
+
token: typing.Optional[str] = None,
|
|
92
|
+
server: typing.Optional[str] = None,
|
|
93
93
|
gitlab: bool = False,
|
|
94
94
|
) -> str:
|
|
95
95
|
"""push comment message to Git system PR/issue
|