mlrun 1.7.1rc4__py3-none-any.whl → 1.8.0rc8__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 +1 -2
- mlrun/artifacts/base.py +46 -12
- mlrun/artifacts/dataset.py +16 -16
- mlrun/artifacts/document.py +334 -0
- mlrun/artifacts/manager.py +15 -13
- mlrun/artifacts/model.py +66 -53
- mlrun/common/constants.py +7 -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 +66 -14
- mlrun/common/schemas/model_monitoring/grafana.py +1 -1
- mlrun/common/schemas/model_monitoring/model_endpoints.py +91 -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 +67 -10
- mlrun/data_types/__init__.py +0 -2
- mlrun/data_types/infer.py +3 -1
- mlrun/data_types/spark.py +2 -1
- mlrun/datastore/__init__.py +0 -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 +0 -2
- mlrun/datastore/targets.py +21 -21
- mlrun/datastore/utils.py +2 -2
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/vectorstore.py +194 -0
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +208 -82
- mlrun/db/factory.py +0 -3
- mlrun/db/httpdb.py +1237 -386
- mlrun/db/nopdb.py +201 -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 +61 -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 +1 -2
- 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 +90 -16
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +279 -59
- 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 +152 -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 +75 -38
- mlrun/projects/project.py +865 -206
- 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 -11
- 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 +74 -65
- 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 +66 -18
- 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 +3 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/METADATA +191 -186
- mlrun-1.8.0rc8.dist-info/RECORD +347 -0
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/WHEEL +1 -1
- 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.1rc4.dist-info/RECORD +0 -351
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/LICENSE +0 -0
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/top_level.txt +0 -0
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
|
|
|
@@ -816,7 +823,9 @@ def _convert_python_package_version_to_image_tag(version: typing.Optional[str]):
|
|
|
816
823
|
|
|
817
824
|
|
|
818
825
|
def enrich_image_url(
|
|
819
|
-
image_url: str,
|
|
826
|
+
image_url: str,
|
|
827
|
+
client_version: Optional[str] = None,
|
|
828
|
+
client_python_version: Optional[str] = None,
|
|
820
829
|
) -> str:
|
|
821
830
|
client_version = _convert_python_package_version_to_image_tag(client_version)
|
|
822
831
|
server_version = _convert_python_package_version_to_image_tag(
|
|
@@ -856,7 +865,7 @@ def enrich_image_url(
|
|
|
856
865
|
|
|
857
866
|
|
|
858
867
|
def resolve_image_tag_suffix(
|
|
859
|
-
mlrun_version: str = None, python_version: str = None
|
|
868
|
+
mlrun_version: Optional[str] = None, python_version: Optional[str] = None
|
|
860
869
|
) -> str:
|
|
861
870
|
"""
|
|
862
871
|
resolves what suffix should be appended to the image tag
|
|
@@ -1175,7 +1184,7 @@ def get_function(function, namespaces, reload_modules: bool = False):
|
|
|
1175
1184
|
def get_handler_extended(
|
|
1176
1185
|
handler_path: str,
|
|
1177
1186
|
context=None,
|
|
1178
|
-
class_args: dict = None,
|
|
1187
|
+
class_args: Optional[dict] = None,
|
|
1179
1188
|
namespaces=None,
|
|
1180
1189
|
reload_modules: bool = False,
|
|
1181
1190
|
):
|
|
@@ -1226,14 +1235,24 @@ def datetime_to_iso(time_obj: Optional[datetime]) -> Optional[str]:
|
|
|
1226
1235
|
return time_obj.isoformat()
|
|
1227
1236
|
|
|
1228
1237
|
|
|
1229
|
-
def enrich_datetime_with_tz_info(timestamp_string):
|
|
1238
|
+
def enrich_datetime_with_tz_info(timestamp_string) -> Optional[datetime]:
|
|
1230
1239
|
if not timestamp_string:
|
|
1231
1240
|
return timestamp_string
|
|
1232
1241
|
|
|
1233
1242
|
if timestamp_string and not mlrun.utils.helpers.has_timezone(timestamp_string):
|
|
1234
1243
|
timestamp_string += datetime.now(timezone.utc).astimezone().strftime("%z")
|
|
1235
1244
|
|
|
1236
|
-
|
|
1245
|
+
for _format in [
|
|
1246
|
+
# e.g: 2021-08-25 12:00:00.000Z
|
|
1247
|
+
"%Y-%m-%d %H:%M:%S.%f%z",
|
|
1248
|
+
# e.g: 2024-11-11 07:44:56+0000
|
|
1249
|
+
"%Y-%m-%d %H:%M:%S%z",
|
|
1250
|
+
]:
|
|
1251
|
+
try:
|
|
1252
|
+
return datetime.strptime(timestamp_string, _format)
|
|
1253
|
+
except ValueError as exc:
|
|
1254
|
+
last_exc = exc
|
|
1255
|
+
raise last_exc
|
|
1237
1256
|
|
|
1238
1257
|
|
|
1239
1258
|
def has_timezone(timestamp):
|
|
@@ -1684,17 +1703,22 @@ def merge_dicts_with_precedence(*dicts: dict) -> dict:
|
|
|
1684
1703
|
|
|
1685
1704
|
|
|
1686
1705
|
def validate_component_version_compatibility(
|
|
1687
|
-
component_name: typing.Literal["iguazio", "nuclio"],
|
|
1706
|
+
component_name: typing.Literal["iguazio", "nuclio", "mlrun-client"],
|
|
1707
|
+
*min_versions: str,
|
|
1708
|
+
mlrun_client_version: Optional[str] = None,
|
|
1688
1709
|
):
|
|
1689
1710
|
"""
|
|
1690
1711
|
:param component_name: Name of the component to validate compatibility for.
|
|
1691
1712
|
:param min_versions: Valid minimum version(s) required, assuming no 2 versions has equal major and minor.
|
|
1713
|
+
:param mlrun_client_version: Client version to validate when component_name is "mlrun-client".
|
|
1692
1714
|
"""
|
|
1693
1715
|
parsed_min_versions = [
|
|
1694
1716
|
semver.VersionInfo.parse(min_version) for min_version in min_versions
|
|
1695
1717
|
]
|
|
1696
1718
|
parsed_current_version = None
|
|
1697
1719
|
component_current_version = None
|
|
1720
|
+
# For mlrun client we don't assume compatability if we fail to parse the client version
|
|
1721
|
+
assume_compatible = component_name not in ["mlrun-client"]
|
|
1698
1722
|
try:
|
|
1699
1723
|
if component_name == "iguazio":
|
|
1700
1724
|
component_current_version = mlrun.mlconf.igz_version
|
|
@@ -1711,18 +1735,29 @@ def validate_component_version_compatibility(
|
|
|
1711
1735
|
parsed_current_version = semver.VersionInfo.parse(
|
|
1712
1736
|
mlrun.mlconf.nuclio_version
|
|
1713
1737
|
)
|
|
1738
|
+
if component_name == "mlrun-client":
|
|
1739
|
+
# dev version, assume compatible
|
|
1740
|
+
if mlrun_client_version and (
|
|
1741
|
+
mlrun_client_version.startswith("0.0.0+")
|
|
1742
|
+
or "unstable" in mlrun_client_version
|
|
1743
|
+
):
|
|
1744
|
+
return True
|
|
1745
|
+
|
|
1746
|
+
component_current_version = mlrun_client_version
|
|
1747
|
+
parsed_current_version = semver.Version.parse(mlrun_client_version)
|
|
1714
1748
|
if not parsed_current_version:
|
|
1715
|
-
return
|
|
1749
|
+
return assume_compatible
|
|
1716
1750
|
except ValueError:
|
|
1717
1751
|
# only log when version is set but invalid
|
|
1718
1752
|
if component_current_version:
|
|
1719
1753
|
logger.warning(
|
|
1720
|
-
"Unable to parse current version
|
|
1754
|
+
"Unable to parse current version",
|
|
1721
1755
|
component_name=component_name,
|
|
1722
1756
|
current_version=component_current_version,
|
|
1723
1757
|
min_versions=min_versions,
|
|
1758
|
+
assume_compatible=assume_compatible,
|
|
1724
1759
|
)
|
|
1725
|
-
return
|
|
1760
|
+
return assume_compatible
|
|
1726
1761
|
|
|
1727
1762
|
# Feature might have been back-ported e.g. nuclio node selection is supported from
|
|
1728
1763
|
# 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
|
|
@@ -1787,9 +1822,8 @@ def _reload(module, max_recursion_depth):
|
|
|
1787
1822
|
def run_with_retry(
|
|
1788
1823
|
retry_count: int,
|
|
1789
1824
|
func: typing.Callable,
|
|
1790
|
-
retry_on_exceptions:
|
|
1791
|
-
type[Exception],
|
|
1792
|
-
tuple[type[Exception]],
|
|
1825
|
+
retry_on_exceptions: Optional[
|
|
1826
|
+
typing.Union[type[Exception], tuple[type[Exception]]]
|
|
1793
1827
|
] = None,
|
|
1794
1828
|
*args,
|
|
1795
1829
|
**kwargs,
|
|
@@ -1822,3 +1856,17 @@ def run_with_retry(
|
|
|
1822
1856
|
if attempt == retry_count:
|
|
1823
1857
|
raise
|
|
1824
1858
|
raise last_exception
|
|
1859
|
+
|
|
1860
|
+
|
|
1861
|
+
def join_urls(base_url: Optional[str], path: Optional[str]) -> str:
|
|
1862
|
+
"""
|
|
1863
|
+
Joins a base URL with a path, ensuring proper handling of slashes.
|
|
1864
|
+
|
|
1865
|
+
:param base_url: The base URL (e.g., "http://example.com").
|
|
1866
|
+
:param path: The path to append to the base URL (e.g., "/path/to/resource").
|
|
1867
|
+
|
|
1868
|
+
:return: A unified URL with exactly one slash between base_url and path.
|
|
1869
|
+
"""
|
|
1870
|
+
if base_url is None:
|
|
1871
|
+
base_url = ""
|
|
1872
|
+
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
|
|
@@ -28,10 +28,11 @@ class IPythonNotification(NotificationBase):
|
|
|
28
28
|
|
|
29
29
|
def __init__(
|
|
30
30
|
self,
|
|
31
|
-
name: str = None,
|
|
32
|
-
params: dict[str, str] = None,
|
|
31
|
+
name: typing.Optional[str] = None,
|
|
32
|
+
params: typing.Optional[dict[str, str]] = None,
|
|
33
|
+
default_params: typing.Optional[dict[str, str]] = None,
|
|
33
34
|
):
|
|
34
|
-
super().__init__(name, params)
|
|
35
|
+
super().__init__(name, params, default_params)
|
|
35
36
|
self._ipython = None
|
|
36
37
|
try:
|
|
37
38
|
import IPython
|
|
@@ -48,13 +49,13 @@ class IPythonNotification(NotificationBase):
|
|
|
48
49
|
def push(
|
|
49
50
|
self,
|
|
50
51
|
message: str,
|
|
51
|
-
severity: typing.
|
|
52
|
-
mlrun.common.schemas.NotificationSeverity, str
|
|
52
|
+
severity: typing.Optional[
|
|
53
|
+
typing.Union[mlrun.common.schemas.NotificationSeverity, str]
|
|
53
54
|
] = mlrun.common.schemas.NotificationSeverity.INFO,
|
|
54
|
-
runs: typing.Union[mlrun.lists.RunList, list] = None,
|
|
55
|
-
custom_html: str = None,
|
|
56
|
-
alert: mlrun.common.schemas.AlertConfig = None,
|
|
57
|
-
event_data: mlrun.common.schemas.Event = None,
|
|
55
|
+
runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
|
|
56
|
+
custom_html: typing.Optional[typing.Optional[str]] = None,
|
|
57
|
+
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
58
|
+
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
58
59
|
):
|
|
59
60
|
if not self._ipython:
|
|
60
61
|
mlrun.utils.helpers.logger.debug(
|