mlrun 1.7.0rc28__py3-none-any.whl → 1.7.0rc55__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/__main__.py +4 -2
- mlrun/alerts/alert.py +75 -8
- mlrun/artifacts/base.py +1 -0
- mlrun/artifacts/manager.py +9 -2
- mlrun/common/constants.py +4 -1
- mlrun/common/db/sql_session.py +3 -2
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/artifact.py +1 -0
- mlrun/{model_monitoring/application.py → common/formatters/feature_set.py} +20 -6
- mlrun/common/formatters/run.py +3 -0
- mlrun/common/helpers.py +0 -1
- mlrun/common/schemas/__init__.py +3 -1
- mlrun/common/schemas/alert.py +15 -12
- mlrun/common/schemas/api_gateway.py +6 -6
- mlrun/common/schemas/auth.py +5 -0
- mlrun/common/schemas/client_spec.py +0 -1
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/frontend_spec.py +7 -0
- mlrun/common/schemas/function.py +7 -0
- mlrun/common/schemas/model_monitoring/__init__.py +4 -3
- mlrun/common/schemas/model_monitoring/constants.py +41 -26
- mlrun/common/schemas/model_monitoring/model_endpoints.py +23 -47
- mlrun/common/schemas/notification.py +69 -12
- mlrun/common/schemas/project.py +45 -12
- mlrun/common/schemas/workflow.py +10 -2
- mlrun/common/types.py +1 -0
- mlrun/config.py +91 -35
- mlrun/data_types/data_types.py +6 -1
- mlrun/data_types/spark.py +2 -2
- mlrun/data_types/to_pandas.py +57 -25
- mlrun/datastore/__init__.py +1 -0
- mlrun/datastore/alibaba_oss.py +3 -2
- mlrun/datastore/azure_blob.py +125 -37
- mlrun/datastore/base.py +42 -21
- mlrun/datastore/datastore.py +4 -2
- mlrun/datastore/datastore_profile.py +1 -1
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -3
- mlrun/datastore/google_cloud_storage.py +85 -29
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +1 -0
- mlrun/datastore/s3.py +25 -12
- mlrun/datastore/sources.py +76 -4
- mlrun/datastore/spark_utils.py +30 -0
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +102 -131
- mlrun/datastore/v3io.py +1 -0
- mlrun/db/base.py +15 -6
- mlrun/db/httpdb.py +57 -28
- mlrun/db/nopdb.py +29 -5
- mlrun/errors.py +20 -3
- mlrun/execution.py +46 -5
- mlrun/feature_store/api.py +25 -1
- mlrun/feature_store/common.py +6 -11
- mlrun/feature_store/feature_vector.py +3 -1
- mlrun/feature_store/retrieval/job.py +4 -1
- mlrun/feature_store/retrieval/spark_merger.py +10 -39
- mlrun/feature_store/steps.py +8 -0
- mlrun/frameworks/_common/plan.py +3 -3
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +2 -3
- mlrun/frameworks/sklearn/mlrun_interface.py +13 -3
- mlrun/k8s_utils.py +48 -2
- mlrun/launcher/client.py +6 -6
- mlrun/launcher/local.py +2 -2
- mlrun/model.py +215 -34
- mlrun/model_monitoring/api.py +38 -24
- mlrun/model_monitoring/applications/__init__.py +1 -2
- mlrun/model_monitoring/applications/_application_steps.py +60 -29
- mlrun/model_monitoring/applications/base.py +2 -174
- mlrun/model_monitoring/applications/context.py +197 -70
- mlrun/model_monitoring/applications/evidently_base.py +11 -85
- mlrun/model_monitoring/applications/histogram_data_drift.py +21 -16
- mlrun/model_monitoring/applications/results.py +4 -4
- mlrun/model_monitoring/controller.py +110 -282
- mlrun/model_monitoring/db/stores/__init__.py +8 -3
- mlrun/model_monitoring/db/stores/base/store.py +3 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +9 -7
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +18 -3
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +43 -23
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +48 -35
- mlrun/model_monitoring/db/tsdb/__init__.py +7 -2
- mlrun/model_monitoring/db/tsdb/base.py +147 -15
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +94 -55
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +0 -3
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +144 -38
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +44 -3
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +246 -57
- mlrun/model_monitoring/helpers.py +70 -50
- mlrun/model_monitoring/stream_processing.py +96 -195
- mlrun/model_monitoring/writer.py +13 -5
- mlrun/package/packagers/default_packager.py +2 -2
- mlrun/projects/operations.py +16 -8
- mlrun/projects/pipelines.py +126 -115
- mlrun/projects/project.py +286 -129
- mlrun/render.py +3 -3
- mlrun/run.py +38 -19
- mlrun/runtimes/__init__.py +19 -8
- mlrun/runtimes/base.py +4 -1
- mlrun/runtimes/daskjob.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -1
- mlrun/runtimes/kubejob.py +6 -6
- mlrun/runtimes/local.py +12 -5
- mlrun/runtimes/nuclio/api_gateway.py +68 -8
- mlrun/runtimes/nuclio/application/application.py +307 -70
- mlrun/runtimes/nuclio/function.py +63 -14
- mlrun/runtimes/nuclio/serving.py +10 -10
- mlrun/runtimes/pod.py +25 -19
- mlrun/runtimes/remotesparkjob.py +2 -5
- mlrun/runtimes/sparkjob/spark3job.py +16 -17
- mlrun/runtimes/utils.py +34 -0
- mlrun/serving/routers.py +2 -5
- mlrun/serving/server.py +37 -19
- mlrun/serving/states.py +30 -3
- mlrun/serving/v2_serving.py +44 -35
- mlrun/track/trackers/mlflow_tracker.py +5 -0
- mlrun/utils/async_http.py +1 -1
- mlrun/utils/db.py +18 -0
- mlrun/utils/helpers.py +150 -36
- mlrun/utils/http.py +1 -1
- mlrun/utils/notifications/notification/__init__.py +0 -1
- mlrun/utils/notifications/notification/webhook.py +8 -1
- mlrun/utils/notifications/notification_pusher.py +1 -1
- mlrun/utils/v3io_clients.py +2 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc28.dist-info → mlrun-1.7.0rc55.dist-info}/METADATA +153 -66
- {mlrun-1.7.0rc28.dist-info → mlrun-1.7.0rc55.dist-info}/RECORD +131 -134
- {mlrun-1.7.0rc28.dist-info → mlrun-1.7.0rc55.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -271
- mlrun/model_monitoring/controller_handler.py +0 -37
- mlrun/model_monitoring/evidently_application.py +0 -20
- mlrun/model_monitoring/prometheus.py +0 -216
- {mlrun-1.7.0rc28.dist-info → mlrun-1.7.0rc55.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc28.dist-info → mlrun-1.7.0rc55.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc28.dist-info → mlrun-1.7.0rc55.dist-info}/top_level.txt +0 -0
mlrun/db/httpdb.py
CHANGED
|
@@ -525,10 +525,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
525
525
|
server_cfg.get("external_platform_tracking")
|
|
526
526
|
or config.external_platform_tracking
|
|
527
527
|
)
|
|
528
|
-
config.model_endpoint_monitoring.store_type = (
|
|
529
|
-
server_cfg.get("model_endpoint_monitoring_store_type")
|
|
530
|
-
or config.model_endpoint_monitoring.store_type
|
|
531
|
-
)
|
|
532
528
|
config.model_endpoint_monitoring.endpoint_store_connection = (
|
|
533
529
|
server_cfg.get("model_endpoint_monitoring_endpoint_store_connection")
|
|
534
530
|
or config.model_endpoint_monitoring.endpoint_store_connection
|
|
@@ -1015,7 +1011,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1015
1011
|
"format": format_,
|
|
1016
1012
|
"tag": tag,
|
|
1017
1013
|
"tree": tree,
|
|
1018
|
-
"uid": uid,
|
|
1014
|
+
"object-uid": uid,
|
|
1019
1015
|
}
|
|
1020
1016
|
if iter is not None:
|
|
1021
1017
|
params["iter"] = str(iter)
|
|
@@ -1033,6 +1029,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1033
1029
|
mlrun.common.schemas.artifact.ArtifactsDeletionStrategies.metadata_only
|
|
1034
1030
|
),
|
|
1035
1031
|
secrets: dict = None,
|
|
1032
|
+
iter=None,
|
|
1036
1033
|
):
|
|
1037
1034
|
"""Delete an artifact.
|
|
1038
1035
|
|
|
@@ -1050,7 +1047,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1050
1047
|
"key": key,
|
|
1051
1048
|
"tag": tag,
|
|
1052
1049
|
"tree": tree,
|
|
1053
|
-
"uid": uid,
|
|
1050
|
+
"object-uid": uid,
|
|
1051
|
+
"iter": iter,
|
|
1054
1052
|
"deletion_strategy": deletion_strategy,
|
|
1055
1053
|
}
|
|
1056
1054
|
error = f"del artifact {project}/{key}"
|
|
@@ -1069,8 +1067,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1069
1067
|
project=None,
|
|
1070
1068
|
tag=None,
|
|
1071
1069
|
labels: Optional[Union[dict[str, str], list[str]]] = None,
|
|
1072
|
-
since=None,
|
|
1073
|
-
until=None,
|
|
1070
|
+
since: Optional[datetime] = None,
|
|
1071
|
+
until: Optional[datetime] = None,
|
|
1074
1072
|
iter: int = None,
|
|
1075
1073
|
best_iteration: bool = False,
|
|
1076
1074
|
kind: str = None,
|
|
@@ -1100,8 +1098,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1100
1098
|
:param tag: Return artifacts assigned this tag.
|
|
1101
1099
|
:param labels: Return artifacts that have these labels. Labels can either be a dictionary {"label": "value"} or
|
|
1102
1100
|
a list of "label=value" (match label key and value) or "label" (match just label key) strings.
|
|
1103
|
-
:param since:
|
|
1104
|
-
:param until:
|
|
1101
|
+
:param since: Return artifacts updated after this date (as datetime object).
|
|
1102
|
+
:param until: Return artifacts updated before this date (as datetime object).
|
|
1105
1103
|
:param iter: Return artifacts from a specific iteration (where ``iter=0`` means the root iteration). If
|
|
1106
1104
|
``None`` (default) return artifacts from all iterations.
|
|
1107
1105
|
:param best_iteration: Returns the artifact which belongs to the best iteration of a given run, in the case of
|
|
@@ -1135,6 +1133,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1135
1133
|
"format": format_,
|
|
1136
1134
|
"producer_uri": producer_uri,
|
|
1137
1135
|
"limit": limit,
|
|
1136
|
+
"since": datetime_to_iso(since),
|
|
1137
|
+
"until": datetime_to_iso(until),
|
|
1138
1138
|
}
|
|
1139
1139
|
error = "list artifacts"
|
|
1140
1140
|
endpoint_path = f"projects/{project}/artifacts"
|
|
@@ -1251,13 +1251,17 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1251
1251
|
function_name=name,
|
|
1252
1252
|
)
|
|
1253
1253
|
|
|
1254
|
-
def list_functions(
|
|
1254
|
+
def list_functions(
|
|
1255
|
+
self, name=None, project=None, tag=None, labels=None, since=None, until=None
|
|
1256
|
+
):
|
|
1255
1257
|
"""Retrieve a list of functions, filtered by specific criteria.
|
|
1256
1258
|
|
|
1257
1259
|
:param name: Return only functions with a specific name.
|
|
1258
1260
|
:param project: Return functions belonging to this project. If not specified, the default project is used.
|
|
1259
|
-
:param tag: Return function versions with specific tags.
|
|
1261
|
+
:param tag: Return function versions with specific tags. To return only tagged functions, set tag to ``"*"``.
|
|
1260
1262
|
:param labels: Return functions that have specific labels assigned to them.
|
|
1263
|
+
:param since: Return functions updated after this date (as datetime object).
|
|
1264
|
+
:param until: Return functions updated before this date (as datetime object).
|
|
1261
1265
|
:returns: List of function objects (as dictionary).
|
|
1262
1266
|
"""
|
|
1263
1267
|
project = project or config.default_project
|
|
@@ -1265,6 +1269,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1265
1269
|
"name": name,
|
|
1266
1270
|
"tag": tag,
|
|
1267
1271
|
"label": labels or [],
|
|
1272
|
+
"since": datetime_to_iso(since),
|
|
1273
|
+
"until": datetime_to_iso(until),
|
|
1268
1274
|
}
|
|
1269
1275
|
error = "list functions"
|
|
1270
1276
|
path = f"projects/{project}/functions"
|
|
@@ -1364,20 +1370,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1364
1370
|
:returns: :py:class:`~mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput` listing the runtime resources
|
|
1365
1371
|
that were removed.
|
|
1366
1372
|
"""
|
|
1367
|
-
if grace_period is None:
|
|
1368
|
-
grace_period = config.runtime_resources_deletion_grace_period
|
|
1369
|
-
logger.info(
|
|
1370
|
-
"Using default grace period for runtime resources deletion",
|
|
1371
|
-
grace_period=grace_period,
|
|
1372
|
-
)
|
|
1373
|
-
|
|
1374
1373
|
params = {
|
|
1375
1374
|
"label-selector": label_selector,
|
|
1376
1375
|
"kind": kind,
|
|
1377
1376
|
"object-id": object_id,
|
|
1378
1377
|
"force": force,
|
|
1379
|
-
"grace-period": grace_period,
|
|
1380
1378
|
}
|
|
1379
|
+
if grace_period is not None:
|
|
1380
|
+
params["grace-period"] = grace_period
|
|
1381
1381
|
error = "Failed deleting runtime resources"
|
|
1382
1382
|
project_path = project if project else "*"
|
|
1383
1383
|
response = self.api_call(
|
|
@@ -1676,7 +1676,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
1676
1676
|
last_log_timestamp = float(
|
|
1677
1677
|
resp.headers.get("x-mlrun-last-timestamp", "0.0")
|
|
1678
1678
|
)
|
|
1679
|
-
if func.kind in mlrun.runtimes.RuntimeKinds.
|
|
1679
|
+
if func.kind in mlrun.runtimes.RuntimeKinds.pure_nuclio_deployed_runtimes():
|
|
1680
1680
|
mlrun.runtimes.nuclio.function.enrich_nuclio_function_from_headers(
|
|
1681
1681
|
func, resp.headers
|
|
1682
1682
|
)
|
|
@@ -2235,6 +2235,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2235
2235
|
partition_order: Union[
|
|
2236
2236
|
mlrun.common.schemas.OrderType, str
|
|
2237
2237
|
] = mlrun.common.schemas.OrderType.desc,
|
|
2238
|
+
format_: Union[
|
|
2239
|
+
str, mlrun.common.formatters.FeatureSetFormat
|
|
2240
|
+
] = mlrun.common.formatters.FeatureSetFormat.full,
|
|
2238
2241
|
) -> list[FeatureSet]:
|
|
2239
2242
|
"""Retrieve a list of feature-sets matching the criteria provided.
|
|
2240
2243
|
|
|
@@ -2252,6 +2255,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2252
2255
|
:param partition_sort_by: What field to sort the results by, within each partition defined by `partition_by`.
|
|
2253
2256
|
Currently the only allowed value are `created` and `updated`.
|
|
2254
2257
|
:param partition_order: Order of sorting within partitions - `asc` or `desc`. Default is `desc`.
|
|
2258
|
+
:param format_: Format of the results. Possible values are:
|
|
2259
|
+
- ``minimal`` - Return minimal feature set objects, not including stats and preview for each feature set.
|
|
2260
|
+
- ``full`` - Return full feature set objects.
|
|
2255
2261
|
:returns: List of matching :py:class:`~mlrun.feature_store.FeatureSet` objects.
|
|
2256
2262
|
"""
|
|
2257
2263
|
|
|
@@ -2264,6 +2270,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2264
2270
|
"entity": entities or [],
|
|
2265
2271
|
"feature": features or [],
|
|
2266
2272
|
"label": labels or [],
|
|
2273
|
+
"format": format_,
|
|
2267
2274
|
}
|
|
2268
2275
|
if partition_by:
|
|
2269
2276
|
params.update(
|
|
@@ -2747,7 +2754,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2747
2754
|
deletion_strategy: Union[
|
|
2748
2755
|
str, mlrun.common.schemas.DeletionStrategy
|
|
2749
2756
|
] = mlrun.common.schemas.DeletionStrategy.default(),
|
|
2750
|
-
):
|
|
2757
|
+
) -> None:
|
|
2751
2758
|
"""Delete a project.
|
|
2752
2759
|
|
|
2753
2760
|
:param name: Name of the project to delete.
|
|
@@ -2766,7 +2773,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2766
2773
|
"DELETE", f"projects/{name}", error_message, headers=headers, version="v2"
|
|
2767
2774
|
)
|
|
2768
2775
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
2769
|
-
logger.info("
|
|
2776
|
+
logger.info("Waiting for project to be deleted", project_name=name)
|
|
2770
2777
|
background_task = mlrun.common.schemas.BackgroundTask(**response.json())
|
|
2771
2778
|
background_task = self._wait_for_background_task_to_reach_terminal_state(
|
|
2772
2779
|
background_task.metadata.name
|
|
@@ -2776,10 +2783,17 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2776
2783
|
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
2777
2784
|
):
|
|
2778
2785
|
logger.info("Project deleted", project_name=name)
|
|
2779
|
-
|
|
2786
|
+
elif (
|
|
2787
|
+
background_task.status.state
|
|
2788
|
+
== mlrun.common.schemas.BackgroundTaskState.failed
|
|
2789
|
+
):
|
|
2790
|
+
logger.error(
|
|
2791
|
+
"Project deletion failed",
|
|
2792
|
+
project_name=name,
|
|
2793
|
+
error=background_task.status.error,
|
|
2794
|
+
)
|
|
2780
2795
|
elif response.status_code == http.HTTPStatus.NO_CONTENT:
|
|
2781
2796
|
logger.info("Project deleted", project_name=name)
|
|
2782
|
-
return
|
|
2783
2797
|
|
|
2784
2798
|
def store_project(
|
|
2785
2799
|
self,
|
|
@@ -3370,7 +3384,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3370
3384
|
By default, the image is mlrun/mlrun.
|
|
3371
3385
|
"""
|
|
3372
3386
|
self.api_call(
|
|
3373
|
-
method=mlrun.common.types.HTTPMethod.
|
|
3387
|
+
method=mlrun.common.types.HTTPMethod.PATCH,
|
|
3374
3388
|
path=f"projects/{project}/model-monitoring/model-monitoring-controller",
|
|
3375
3389
|
params={
|
|
3376
3390
|
"base_period": base_period,
|
|
@@ -3465,7 +3479,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3465
3479
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
3466
3480
|
if delete_resources:
|
|
3467
3481
|
logger.info(
|
|
3468
|
-
"Model Monitoring is being
|
|
3482
|
+
"Model Monitoring is being disabled",
|
|
3469
3483
|
project_name=project,
|
|
3470
3484
|
)
|
|
3471
3485
|
if delete_user_applications:
|
|
@@ -3544,17 +3558,19 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3544
3558
|
self,
|
|
3545
3559
|
project: str,
|
|
3546
3560
|
credentials: dict[str, str],
|
|
3561
|
+
replace_creds: bool,
|
|
3547
3562
|
) -> None:
|
|
3548
3563
|
"""
|
|
3549
3564
|
Set the credentials for the model monitoring application.
|
|
3550
3565
|
|
|
3551
3566
|
:param project: Project name.
|
|
3552
3567
|
:param credentials: Credentials to set.
|
|
3568
|
+
:param replace_creds: If True, will override the existing credentials.
|
|
3553
3569
|
"""
|
|
3554
3570
|
self.api_call(
|
|
3555
3571
|
method=mlrun.common.types.HTTPMethod.POST,
|
|
3556
3572
|
path=f"projects/{project}/model-monitoring/set-model-monitoring-credentials",
|
|
3557
|
-
params={**credentials},
|
|
3573
|
+
params={**credentials, "replace_creds": replace_creds},
|
|
3558
3574
|
)
|
|
3559
3575
|
|
|
3560
3576
|
def create_hub_source(
|
|
@@ -4181,6 +4197,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4181
4197
|
:param event_data: The data of the event.
|
|
4182
4198
|
:param project: The project that the event belongs to.
|
|
4183
4199
|
"""
|
|
4200
|
+
if mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.disabled:
|
|
4201
|
+
logger.warning("Alerts are disabled, event will not be generated")
|
|
4202
|
+
|
|
4184
4203
|
project = project or config.default_project
|
|
4185
4204
|
endpoint_path = f"projects/{project}/events/{name}"
|
|
4186
4205
|
error_message = f"post event {project}/events/{name}"
|
|
@@ -4204,6 +4223,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4204
4223
|
:param project: The project that the alert belongs to.
|
|
4205
4224
|
:returns: The created/modified alert.
|
|
4206
4225
|
"""
|
|
4226
|
+
if not alert_data:
|
|
4227
|
+
raise mlrun.errors.MLRunInvalidArgumentError("Alert data must be provided")
|
|
4228
|
+
|
|
4229
|
+
if mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.disabled:
|
|
4230
|
+
logger.warning(
|
|
4231
|
+
"Alerts are disabled, alert will still be stored but will not be triggered"
|
|
4232
|
+
)
|
|
4233
|
+
|
|
4207
4234
|
project = project or config.default_project
|
|
4208
4235
|
endpoint_path = f"projects/{project}/alerts/{alert_name}"
|
|
4209
4236
|
error_message = f"put alert {project}/alerts/{alert_name}"
|
|
@@ -4212,6 +4239,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4212
4239
|
if isinstance(alert_data, AlertConfig)
|
|
4213
4240
|
else AlertConfig.from_dict(alert_data)
|
|
4214
4241
|
)
|
|
4242
|
+
# Validation is necessary here because users can directly invoke this function
|
|
4243
|
+
# through `mlrun.get_run_db().store_alert_config()`.
|
|
4215
4244
|
alert_instance.validate_required_fields()
|
|
4216
4245
|
|
|
4217
4246
|
alert_data = alert_instance.to_dict()
|
mlrun/db/nopdb.py
CHANGED
|
@@ -21,6 +21,7 @@ import mlrun.common.formatters
|
|
|
21
21
|
import mlrun.common.runtimes.constants
|
|
22
22
|
import mlrun.common.schemas
|
|
23
23
|
import mlrun.errors
|
|
24
|
+
import mlrun.lists
|
|
24
25
|
|
|
25
26
|
from ..config import config
|
|
26
27
|
from ..utils import logger
|
|
@@ -73,6 +74,22 @@ class NopDB(RunDBInterface):
|
|
|
73
74
|
def abort_run(self, uid, project="", iter=0, timeout=45, status_text=""):
|
|
74
75
|
pass
|
|
75
76
|
|
|
77
|
+
def list_runtime_resources(
|
|
78
|
+
self,
|
|
79
|
+
project: Optional[str] = None,
|
|
80
|
+
label_selector: Optional[str] = None,
|
|
81
|
+
kind: Optional[str] = None,
|
|
82
|
+
object_id: Optional[str] = None,
|
|
83
|
+
group_by: Optional[
|
|
84
|
+
mlrun.common.schemas.ListRuntimeResourcesGroupByField
|
|
85
|
+
] = None,
|
|
86
|
+
) -> Union[
|
|
87
|
+
mlrun.common.schemas.RuntimeResourcesOutput,
|
|
88
|
+
mlrun.common.schemas.GroupedByJobRuntimeResourcesOutput,
|
|
89
|
+
mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput,
|
|
90
|
+
]:
|
|
91
|
+
return []
|
|
92
|
+
|
|
76
93
|
def read_run(
|
|
77
94
|
self,
|
|
78
95
|
uid,
|
|
@@ -108,7 +125,7 @@ class NopDB(RunDBInterface):
|
|
|
108
125
|
max_partitions: int = 0,
|
|
109
126
|
with_notifications: bool = False,
|
|
110
127
|
):
|
|
111
|
-
|
|
128
|
+
return mlrun.lists.RunList()
|
|
112
129
|
|
|
113
130
|
def del_run(self, uid, project="", iter=0):
|
|
114
131
|
pass
|
|
@@ -149,7 +166,7 @@ class NopDB(RunDBInterface):
|
|
|
149
166
|
format_: mlrun.common.formatters.ArtifactFormat = mlrun.common.formatters.ArtifactFormat.full,
|
|
150
167
|
limit: int = None,
|
|
151
168
|
):
|
|
152
|
-
|
|
169
|
+
return mlrun.lists.ArtifactList()
|
|
153
170
|
|
|
154
171
|
def del_artifact(
|
|
155
172
|
self,
|
|
@@ -162,6 +179,7 @@ class NopDB(RunDBInterface):
|
|
|
162
179
|
mlrun.common.schemas.artifact.ArtifactsDeletionStrategies.metadata_only
|
|
163
180
|
),
|
|
164
181
|
secrets: dict = None,
|
|
182
|
+
iter=None,
|
|
165
183
|
):
|
|
166
184
|
pass
|
|
167
185
|
|
|
@@ -177,8 +195,10 @@ class NopDB(RunDBInterface):
|
|
|
177
195
|
def delete_function(self, name: str, project: str = ""):
|
|
178
196
|
pass
|
|
179
197
|
|
|
180
|
-
def list_functions(
|
|
181
|
-
|
|
198
|
+
def list_functions(
|
|
199
|
+
self, name=None, project="", tag="", labels=None, since=None, until=None
|
|
200
|
+
):
|
|
201
|
+
return []
|
|
182
202
|
|
|
183
203
|
def tag_objects(
|
|
184
204
|
self,
|
|
@@ -306,6 +326,9 @@ class NopDB(RunDBInterface):
|
|
|
306
326
|
partition_order: Union[
|
|
307
327
|
mlrun.common.schemas.OrderType, str
|
|
308
328
|
] = mlrun.common.schemas.OrderType.desc,
|
|
329
|
+
format_: Union[
|
|
330
|
+
str, mlrun.common.formatters.FeatureSetFormat
|
|
331
|
+
] = mlrun.common.formatters.FeatureSetFormat.full,
|
|
309
332
|
) -> list[dict]:
|
|
310
333
|
pass
|
|
311
334
|
|
|
@@ -418,7 +441,7 @@ class NopDB(RunDBInterface):
|
|
|
418
441
|
] = mlrun.common.formatters.PipelineFormat.metadata_only,
|
|
419
442
|
page_size: int = None,
|
|
420
443
|
) -> mlrun.common.schemas.PipelinesOutput:
|
|
421
|
-
|
|
444
|
+
return mlrun.common.schemas.PipelinesOutput(runs=[], total_size=0)
|
|
422
445
|
|
|
423
446
|
def create_project_secrets(
|
|
424
447
|
self,
|
|
@@ -737,6 +760,7 @@ class NopDB(RunDBInterface):
|
|
|
737
760
|
self,
|
|
738
761
|
project: str,
|
|
739
762
|
credentials: dict[str, str],
|
|
763
|
+
replace_creds: bool,
|
|
740
764
|
) -> None:
|
|
741
765
|
pass
|
|
742
766
|
|
mlrun/errors.py
CHANGED
|
@@ -29,11 +29,14 @@ class MLRunBaseError(Exception):
|
|
|
29
29
|
pass
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
class
|
|
32
|
+
class MLRunTaskNotReadyError(MLRunBaseError):
|
|
33
33
|
"""indicate we are trying to read a value which is not ready
|
|
34
34
|
or need to come from a job which is in progress"""
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
MLRunTaskNotReady = MLRunTaskNotReadyError # kept for BC only
|
|
38
|
+
|
|
39
|
+
|
|
37
40
|
class MLRunHTTPError(MLRunBaseError, requests.HTTPError):
|
|
38
41
|
def __init__(
|
|
39
42
|
self,
|
|
@@ -137,7 +140,13 @@ def err_to_str(err):
|
|
|
137
140
|
error_strings.append(err_msg)
|
|
138
141
|
err = err.__cause__
|
|
139
142
|
|
|
140
|
-
|
|
143
|
+
err_msg = ", caused by: ".join(error_strings)
|
|
144
|
+
|
|
145
|
+
# in case the error string is longer than 32k, we truncate it
|
|
146
|
+
# the truncation takes the first 16k, then the last 16k characters
|
|
147
|
+
if len(err_msg) > 32_000:
|
|
148
|
+
err_msg = err_msg[:16_000] + "...truncated..." + err_msg[-16_000:]
|
|
149
|
+
return err_msg
|
|
141
150
|
|
|
142
151
|
|
|
143
152
|
# Specific Errors
|
|
@@ -205,7 +214,15 @@ class MLRunTimeoutError(MLRunHTTPStatusError, TimeoutError):
|
|
|
205
214
|
error_status_code = HTTPStatus.GATEWAY_TIMEOUT.value
|
|
206
215
|
|
|
207
216
|
|
|
208
|
-
class
|
|
217
|
+
class MLRunInvalidMMStoreTypeError(MLRunHTTPStatusError, ValueError):
|
|
218
|
+
error_status_code = HTTPStatus.BAD_REQUEST.value
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class MLRunStreamConnectionFailureError(MLRunHTTPStatusError, ValueError):
|
|
222
|
+
error_status_code = HTTPStatus.BAD_REQUEST.value
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class MLRunTSDBConnectionFailureError(MLRunHTTPStatusError, ValueError):
|
|
209
226
|
error_status_code = HTTPStatus.BAD_REQUEST.value
|
|
210
227
|
|
|
211
228
|
|
mlrun/execution.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import logging
|
|
15
16
|
import os
|
|
16
17
|
import uuid
|
|
17
18
|
from copy import deepcopy
|
|
@@ -23,6 +24,7 @@ from dateutil import parser
|
|
|
23
24
|
|
|
24
25
|
import mlrun
|
|
25
26
|
import mlrun.common.constants as mlrun_constants
|
|
27
|
+
import mlrun.common.formatters
|
|
26
28
|
from mlrun.artifacts import ModelArtifact
|
|
27
29
|
from mlrun.datastore.store_resources import get_store_resource
|
|
28
30
|
from mlrun.errors import MLRunInvalidArgumentError
|
|
@@ -78,7 +80,6 @@ class MLClientCtx:
|
|
|
78
80
|
self._tmpfile = tmp
|
|
79
81
|
self._logger = log_stream or logger
|
|
80
82
|
self._log_level = "info"
|
|
81
|
-
self._matrics_db = None
|
|
82
83
|
self._autocommit = autocommit
|
|
83
84
|
self._notifications = []
|
|
84
85
|
self._state_thresholds = {}
|
|
@@ -103,8 +104,7 @@ class MLClientCtx:
|
|
|
103
104
|
self._error = None
|
|
104
105
|
self._commit = ""
|
|
105
106
|
self._host = None
|
|
106
|
-
self._start_time = now_date()
|
|
107
|
-
self._last_update = now_date()
|
|
107
|
+
self._start_time = self._last_update = now_date()
|
|
108
108
|
self._iteration_results = None
|
|
109
109
|
self._children = []
|
|
110
110
|
self._parent = None
|
|
@@ -170,6 +170,8 @@ class MLClientCtx:
|
|
|
170
170
|
@log_level.setter
|
|
171
171
|
def log_level(self, value: str):
|
|
172
172
|
"""Set the logging level, e.g. 'debug', 'info', 'error'"""
|
|
173
|
+
level = logging.getLevelName(value.upper())
|
|
174
|
+
self._logger.set_logger_level(level)
|
|
173
175
|
self._log_level = value
|
|
174
176
|
|
|
175
177
|
@property
|
|
@@ -337,7 +339,7 @@ class MLClientCtx:
|
|
|
337
339
|
"name": self.name,
|
|
338
340
|
"kind": "run",
|
|
339
341
|
"uri": uri,
|
|
340
|
-
"owner": get_in(self._labels,
|
|
342
|
+
"owner": get_in(self._labels, mlrun_constants.MLRunInternalLabels.owner),
|
|
341
343
|
}
|
|
342
344
|
if mlrun_constants.MLRunInternalLabels.workflow in self._labels:
|
|
343
345
|
resp[mlrun_constants.MLRunInternalLabels.workflow] = self._labels[
|
|
@@ -633,7 +635,9 @@ class MLClientCtx:
|
|
|
633
635
|
:param viewer: Kubeflow viewer type
|
|
634
636
|
:param target_path: Absolute target path (instead of using artifact_path + local_path)
|
|
635
637
|
:param src_path: Deprecated, use local_path
|
|
636
|
-
:param upload:
|
|
638
|
+
:param upload: Whether to upload the artifact to the datastore. If not provided, and the `local_path`
|
|
639
|
+
is not a directory, upload occurs by default. Directories are uploaded only when this
|
|
640
|
+
flag is explicitly set to `True`.
|
|
637
641
|
:param labels: A set of key/value labels to tag the artifact with
|
|
638
642
|
:param format: Optional, format to use (e.g. csv, parquet, ..)
|
|
639
643
|
:param db_key: The key to use in the artifact DB table, by default its run name + '_' + key
|
|
@@ -923,6 +927,43 @@ class MLClientCtx:
|
|
|
923
927
|
updates, self._uid, self.project, iter=self._iteration
|
|
924
928
|
)
|
|
925
929
|
|
|
930
|
+
def get_notifications(self, unmask_secret_params=False):
|
|
931
|
+
"""
|
|
932
|
+
Get the list of notifications
|
|
933
|
+
|
|
934
|
+
:param unmask_secret_params: Used as a workaround for sending notification from workflow-runner.
|
|
935
|
+
When used, if the notification will be saved again a new secret will be created.
|
|
936
|
+
"""
|
|
937
|
+
|
|
938
|
+
# Get the full notifications from the DB since the run context does not contain the params due to bloating
|
|
939
|
+
run = self._rundb.read_run(
|
|
940
|
+
self.uid, format_=mlrun.common.formatters.RunFormat.notifications
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
notifications = []
|
|
944
|
+
for notification in run["spec"]["notifications"]:
|
|
945
|
+
notification: mlrun.model.Notification = mlrun.model.Notification.from_dict(
|
|
946
|
+
notification
|
|
947
|
+
)
|
|
948
|
+
# Fill the secret params from the project secret. We cannot use the server side internal secret mechanism
|
|
949
|
+
# here as it is the client side.
|
|
950
|
+
# TODO: This is a workaround to allow the notification to get the secret params from project secret
|
|
951
|
+
# instead of getting them from the internal project secret that should be mounted.
|
|
952
|
+
# We should mount the internal project secret that was created to the workflow-runner
|
|
953
|
+
# and get the secret from there.
|
|
954
|
+
if unmask_secret_params:
|
|
955
|
+
try:
|
|
956
|
+
notification.enrich_unmasked_secret_params_from_project_secret()
|
|
957
|
+
notifications.append(notification)
|
|
958
|
+
except mlrun.errors.MLRunValueError:
|
|
959
|
+
logger.warning(
|
|
960
|
+
"Failed to fill secret params from project secret for notification."
|
|
961
|
+
"Skip this notification.",
|
|
962
|
+
notification=notification.name,
|
|
963
|
+
)
|
|
964
|
+
|
|
965
|
+
return notifications
|
|
966
|
+
|
|
926
967
|
def to_dict(self):
|
|
927
968
|
"""Convert the run context to a dictionary"""
|
|
928
969
|
|
mlrun/feature_store/api.py
CHANGED
|
@@ -230,6 +230,11 @@ def _get_offline_features(
|
|
|
230
230
|
"entity_timestamp_column param "
|
|
231
231
|
"can not be specified without entity_rows param"
|
|
232
232
|
)
|
|
233
|
+
if isinstance(target, BaseStoreTarget) and not target.support_pandas:
|
|
234
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
235
|
+
f"get_offline_features does not support targets that do not support pandas engine."
|
|
236
|
+
f" Target kind: {target.kind}"
|
|
237
|
+
)
|
|
233
238
|
|
|
234
239
|
if isinstance(feature_vector, FeatureVector):
|
|
235
240
|
update_stats = True
|
|
@@ -1032,6 +1037,8 @@ def _ingest_with_spark(
|
|
|
1032
1037
|
try:
|
|
1033
1038
|
import pyspark.sql
|
|
1034
1039
|
|
|
1040
|
+
from mlrun.datastore.spark_utils import check_special_columns_exists
|
|
1041
|
+
|
|
1035
1042
|
if spark is None or spark is True:
|
|
1036
1043
|
# create spark context
|
|
1037
1044
|
|
|
@@ -1044,13 +1051,13 @@ def _ingest_with_spark(
|
|
|
1044
1051
|
|
|
1045
1052
|
spark = (
|
|
1046
1053
|
pyspark.sql.SparkSession.builder.appName(session_name)
|
|
1054
|
+
.config("spark.driver.memory", "2g")
|
|
1047
1055
|
.config("spark.sql.session.timeZone", "UTC")
|
|
1048
1056
|
.getOrCreate()
|
|
1049
1057
|
)
|
|
1050
1058
|
created_spark_context = True
|
|
1051
1059
|
|
|
1052
1060
|
timestamp_key = featureset.spec.timestamp_key
|
|
1053
|
-
|
|
1054
1061
|
if isinstance(source, pd.DataFrame):
|
|
1055
1062
|
df = spark.createDataFrame(source)
|
|
1056
1063
|
elif isinstance(source, pyspark.sql.DataFrame):
|
|
@@ -1080,6 +1087,12 @@ def _ingest_with_spark(
|
|
|
1080
1087
|
target = get_target_driver(target, featureset)
|
|
1081
1088
|
target.set_resource(featureset)
|
|
1082
1089
|
if featureset.spec.passthrough and target.is_offline:
|
|
1090
|
+
check_special_columns_exists(
|
|
1091
|
+
spark_df=df,
|
|
1092
|
+
entities=featureset.spec.entities,
|
|
1093
|
+
timestamp_key=timestamp_key,
|
|
1094
|
+
label_column=featureset.spec.label_column,
|
|
1095
|
+
)
|
|
1083
1096
|
continue
|
|
1084
1097
|
spark_options = target.get_spark_options(
|
|
1085
1098
|
key_columns, timestamp_key, overwrite
|
|
@@ -1090,6 +1103,17 @@ def _ingest_with_spark(
|
|
|
1090
1103
|
df_to_write, key_columns, timestamp_key, spark_options
|
|
1091
1104
|
)
|
|
1092
1105
|
write_format = spark_options.pop("format", None)
|
|
1106
|
+
# We can get to this point if the column exists in different letter cases,
|
|
1107
|
+
# so PySpark will be able to read it, but we still have to raise an exception for it.
|
|
1108
|
+
|
|
1109
|
+
# This check is here and not in to_spark_df because in spark_merger we can have a target
|
|
1110
|
+
# that has different letter cases than the source, like in SnowflakeTarget.
|
|
1111
|
+
check_special_columns_exists(
|
|
1112
|
+
spark_df=df_to_write,
|
|
1113
|
+
entities=featureset.spec.entities,
|
|
1114
|
+
timestamp_key=timestamp_key,
|
|
1115
|
+
label_column=featureset.spec.label_column,
|
|
1116
|
+
)
|
|
1093
1117
|
if overwrite:
|
|
1094
1118
|
write_spark_dataframe_with_options(
|
|
1095
1119
|
spark_options, df_to_write, "overwrite", write_format=write_format
|
mlrun/feature_store/common.py
CHANGED
|
@@ -37,17 +37,12 @@ def parse_feature_string(feature):
|
|
|
37
37
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
38
38
|
f"feature {feature} must be {expected_message}"
|
|
39
39
|
)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
feature_set
|
|
46
|
-
feature_name = splitted[1]
|
|
47
|
-
splitted = feature_name.split(" as ")
|
|
48
|
-
if len(splitted) > 1:
|
|
49
|
-
return feature_set.strip(), splitted[0].strip(), splitted[1].strip()
|
|
50
|
-
return feature_set.strip(), feature_name.strip(), None
|
|
40
|
+
feature_set, feature_name = feature.rsplit(feature_separator, 1)
|
|
41
|
+
feature_set = feature_set.strip()
|
|
42
|
+
split_result = feature_name.split(" as ", 1)
|
|
43
|
+
feature_name = split_result[0].strip()
|
|
44
|
+
alias = split_result[1].strip() if len(split_result) > 1 else None
|
|
45
|
+
return feature_set, feature_name, alias
|
|
51
46
|
|
|
52
47
|
|
|
53
48
|
def parse_project_name_from_feature_string(feature):
|
|
@@ -1086,7 +1086,9 @@ class OfflineVectorResponse:
|
|
|
1086
1086
|
def to_dataframe(self, to_pandas=True):
|
|
1087
1087
|
"""return result as dataframe"""
|
|
1088
1088
|
if self.status != "completed":
|
|
1089
|
-
raise mlrun.errors.
|
|
1089
|
+
raise mlrun.errors.MLRunTaskNotReadyError(
|
|
1090
|
+
"feature vector dataset is not ready"
|
|
1091
|
+
)
|
|
1090
1092
|
return self._merger.get_df(to_pandas=to_pandas)
|
|
1091
1093
|
|
|
1092
1094
|
def to_parquet(self, target_path, **kw):
|
|
@@ -156,7 +156,9 @@ class RemoteVectorResponse:
|
|
|
156
156
|
|
|
157
157
|
def _is_ready(self):
|
|
158
158
|
if self.status != "completed":
|
|
159
|
-
raise mlrun.errors.
|
|
159
|
+
raise mlrun.errors.MLRunTaskNotReadyError(
|
|
160
|
+
"feature vector dataset is not ready"
|
|
161
|
+
)
|
|
160
162
|
self.vector.reload()
|
|
161
163
|
|
|
162
164
|
def to_dataframe(self, columns=None, df_module=None, **kwargs):
|
|
@@ -181,6 +183,7 @@ class RemoteVectorResponse:
|
|
|
181
183
|
file_format = kwargs.get("format")
|
|
182
184
|
if not file_format:
|
|
183
185
|
file_format = self.run.status.results["target"]["kind"]
|
|
186
|
+
|
|
184
187
|
df = mlrun.get_dataitem(self.target_uri).as_df(
|
|
185
188
|
columns=columns, df_module=df_module, format=file_format, **kwargs
|
|
186
189
|
)
|