mlrun 1.10.0rc1__py3-none-any.whl → 1.10.0rc2__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.

@@ -14,19 +14,18 @@
14
14
 
15
15
  import json
16
16
  import posixpath
17
- import uuid
18
17
  import warnings
19
18
  from abc import ABC
19
+ from tempfile import NamedTemporaryFile
20
+ from typing import Optional
20
21
 
21
- import pandas as pd
22
22
  import semver
23
- from evidently.ui.storage.local.base import METADATA_PATH, FSLocation
24
23
 
25
24
  import mlrun.model_monitoring.applications.base as mm_base
26
25
  import mlrun.model_monitoring.applications.context as mm_context
27
- from mlrun.errors import MLRunIncompatibleVersionError
26
+ from mlrun.errors import MLRunIncompatibleVersionError, MLRunValueError
28
27
 
29
- SUPPORTED_EVIDENTLY_VERSION = semver.Version.parse("0.6.0")
28
+ SUPPORTED_EVIDENTLY_VERSION = semver.Version.parse("0.7.5")
30
29
 
31
30
 
32
31
  def _check_evidently_version(*, cur: semver.Version, ref: semver.Version) -> None:
@@ -60,36 +59,66 @@ except ModuleNotFoundError:
60
59
 
61
60
 
62
61
  if _HAS_EVIDENTLY:
63
- from evidently.suite.base_suite import Display
64
- from evidently.ui.type_aliases import STR_UUID
65
- from evidently.ui.workspace import Workspace
66
- from evidently.utils.dashboard import TemplateParams, file_html_template
62
+ from evidently.core.report import Snapshot
63
+ from evidently.legacy.ui.storage.local.base import METADATA_PATH, FSLocation
64
+ from evidently.ui.workspace import (
65
+ STR_UUID,
66
+ CloudWorkspace,
67
+ Project,
68
+ Workspace,
69
+ WorkspaceBase,
70
+ )
67
71
 
68
72
 
69
73
  class EvidentlyModelMonitoringApplicationBase(
70
74
  mm_base.ModelMonitoringApplicationBase, ABC
71
75
  ):
72
76
  def __init__(
73
- self, evidently_workspace_path: str, evidently_project_id: "STR_UUID"
77
+ self,
78
+ evidently_project_id: "STR_UUID",
79
+ evidently_workspace_path: Optional[str] = None,
80
+ cloud_workspace: bool = False,
74
81
  ) -> None:
75
82
  """
76
- A class for integrating Evidently for mlrun model monitoring within a monitoring application.
77
- Note: evidently is not installed by default in the mlrun/mlrun image.
78
- It must be installed separately to use this class.
83
+ A class for integrating Evidently for MLRun model monitoring within a monitoring application.
84
+
85
+ .. note::
86
+
87
+ The ``evidently`` package is not installed by default in the mlrun/mlrun image.
88
+ It must be installed separately to use this class.
79
89
 
80
- :param evidently_workspace_path: (str) The path to the Evidently workspace.
81
90
  :param evidently_project_id: (str) The ID of the Evidently project.
91
+ :param evidently_workspace_path: (str) The path to the Evidently workspace.
92
+ :param cloud_workspace: (bool) Whether the workspace is an Evidently Cloud workspace.
82
93
  """
83
-
84
- # TODO : more then one project (mep -> project)
85
94
  if not _HAS_EVIDENTLY:
86
95
  raise ModuleNotFoundError("Evidently is not installed - the app cannot run")
87
- self._log_location(evidently_workspace_path)
88
- self.evidently_workspace = Workspace.create(evidently_workspace_path)
96
+ self.evidently_workspace_path = evidently_workspace_path
97
+ if cloud_workspace:
98
+ self.get_workspace = self.get_cloud_workspace
99
+ self.evidently_workspace = self.get_workspace()
89
100
  self.evidently_project_id = evidently_project_id
90
- self.evidently_project = self.evidently_workspace.get_project(
91
- evidently_project_id
92
- )
101
+ self.evidently_project = self.load_project()
102
+
103
+ def load_project(self) -> Project:
104
+ """Load the Evidently project."""
105
+ return self.evidently_workspace.get_project(self.evidently_project_id)
106
+
107
+ def get_workspace(self) -> WorkspaceBase:
108
+ """Get the Evidently workspace. Override this method for customize access to the workspace."""
109
+ if self.evidently_workspace_path:
110
+ self._log_location(self.evidently_workspace_path)
111
+ return Workspace.create(self.evidently_workspace_path)
112
+ else:
113
+ raise MLRunValueError(
114
+ "A local workspace could not be created as `evidently_workspace_path` is not set.\n"
115
+ "If you intend to use a cloud workspace, please use `cloud_workspace=True` and set the "
116
+ "`EVIDENTLY_API_KEY` environment variable. In other cases, override this method."
117
+ )
118
+
119
+ def get_cloud_workspace(self) -> CloudWorkspace:
120
+ """Load the Evidently cloud workspace according to the `EVIDENTLY_API_KEY` environment variable."""
121
+ return CloudWorkspace()
93
122
 
94
123
  @staticmethod
95
124
  def _log_location(evidently_workspace_path):
@@ -128,7 +157,7 @@ class EvidentlyModelMonitoringApplicationBase(
128
157
  @staticmethod
129
158
  def log_evidently_object(
130
159
  monitoring_context: mm_context.MonitoringApplicationContext,
131
- evidently_object: "Display",
160
+ evidently_object: "Snapshot",
132
161
  artifact_name: str,
133
162
  unique_per_endpoint: bool = True,
134
163
  ) -> None:
@@ -141,56 +170,15 @@ class EvidentlyModelMonitoringApplicationBase(
141
170
  This method should be called on special occasions only.
142
171
 
143
172
  :param monitoring_context: (MonitoringApplicationContext) The monitoring context to process.
144
- :param evidently_object: (Display) The Evidently display to log, e.g. a report or a test suite object.
145
- :param artifact_name: (str) The name for the logged artifact.
146
- :param unique_per_endpoint: by default ``True``, we will log different artifact for each model endpoint,
147
- set to ``False`` without changing item key will cause artifact override.
148
- """
149
- evidently_object_html = evidently_object.get_html()
150
- monitoring_context.log_artifact(
151
- artifact_name,
152
- body=evidently_object_html.encode("utf-8"),
153
- format="html",
154
- unique_per_endpoint=unique_per_endpoint,
155
- )
156
-
157
- def log_project_dashboard(
158
- self,
159
- monitoring_context: mm_context.MonitoringApplicationContext,
160
- timestamp_start: pd.Timestamp,
161
- timestamp_end: pd.Timestamp,
162
- artifact_name: str = "dashboard",
163
- unique_per_endpoint: bool = True,
164
- ) -> None:
165
- """
166
- Logs an Evidently project dashboard.
167
-
168
- .. caution::
169
-
170
- Logging Evidently dashboards in every model monitoring window may cause scale issues.
171
- This method should be called on special occasions only.
172
-
173
- :param monitoring_context: (MonitoringApplicationContext) The monitoring context to process.
174
- :param timestamp_start: (pd.Timestamp) The start timestamp for the dashboard data.
175
- :param timestamp_end: (pd.Timestamp) The end timestamp for the dashboard data.
173
+ :param evidently_object: (Snapshot) The Evidently run to log, e.g. a report run.
176
174
  :param artifact_name: (str) The name for the logged artifact.
177
175
  :param unique_per_endpoint: by default ``True``, we will log different artifact for each model endpoint,
178
176
  set to ``False`` without changing item key will cause artifact override.
179
177
  """
180
-
181
- dashboard_info = self.evidently_project.build_dashboard_info(
182
- timestamp_start, timestamp_end
183
- )
184
- template_params = TemplateParams(
185
- dashboard_id="pd_" + str(uuid.uuid4()).replace("-", ""),
186
- dashboard_info=dashboard_info,
187
- additional_graphs={},
188
- )
189
-
190
- dashboard_html = file_html_template(params=template_params)
191
- monitoring_context.log_artifact(
192
- artifact_name,
193
- body=dashboard_html.encode("utf-8"),
194
- format="html",
195
- unique_per_endpoint=unique_per_endpoint,
196
- )
178
+ with NamedTemporaryFile(suffix=".html") as file:
179
+ evidently_object.save_html(filename=file.name)
180
+ monitoring_context.log_artifact(
181
+ artifact_name,
182
+ local_path=file.name,
183
+ unique_per_endpoint=unique_per_endpoint,
184
+ )
@@ -25,6 +25,7 @@ from types import TracebackType
25
25
  from typing import Any, NamedTuple, Optional, Union, cast
26
26
 
27
27
  import nuclio_sdk
28
+ import pandas as pd
28
29
 
29
30
  import mlrun
30
31
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
@@ -673,9 +674,15 @@ class MonitoringApplicationController:
673
674
  """
674
675
  logger.info("Starting monitoring controller chief")
675
676
  applications_names = []
676
- endpoints = self.project_obj.list_model_endpoints(
677
- metric_list=["last_request"]
678
- ).endpoints
677
+ endpoints = self.project_obj.list_model_endpoints(tsdb_metrics=False).endpoints
678
+ last_request_dict = self.tsdb_connector.get_last_request(
679
+ endpoint_ids=[mep.metadata.uid for mep in endpoints]
680
+ )
681
+ if isinstance(last_request_dict, pd.DataFrame):
682
+ last_request_dict = last_request_dict.set_index(
683
+ mm_constants.EventFieldType.ENDPOINT_ID
684
+ )[mm_constants.ModelEndpointSchema.LAST_REQUEST].to_dict()
685
+
679
686
  if not endpoints:
680
687
  logger.info("No model endpoints found", project=self.project)
681
688
  return
@@ -721,16 +728,22 @@ class MonitoringApplicationController:
721
728
  with schedules.ModelMonitoringSchedulesFileChief(
722
729
  self.project
723
730
  ) as schedule_file:
724
- futures = {
725
- pool.submit(
726
- self.endpoint_to_regular_event,
727
- endpoint,
728
- policy,
729
- set(applications_names),
730
- schedule_file,
731
- ): endpoint
732
- for endpoint in endpoints
733
- }
731
+ for endpoint in endpoints:
732
+ last_request = last_request_dict.get(endpoint.metadata.uid, None)
733
+ if isinstance(last_request, float):
734
+ last_request = pd.to_datetime(last_request, unit="s", utc=True)
735
+ endpoint.status.last_request = (
736
+ last_request or endpoint.status.last_request
737
+ )
738
+ futures = {
739
+ pool.submit(
740
+ self.endpoint_to_regular_event,
741
+ endpoint,
742
+ policy,
743
+ set(applications_names),
744
+ schedule_file,
745
+ ): endpoint
746
+ }
734
747
  for future in concurrent.futures.as_completed(futures):
735
748
  if future.exception():
736
749
  exception = future.exception()
@@ -455,12 +455,20 @@ class V3IOTSDBConnector(TSDBConnector):
455
455
  # Delete all tables
456
456
  tables = mm_schemas.V3IOTSDBTables.list()
457
457
  for table_to_delete in tables:
458
- try:
459
- self.frames_client.delete(backend=_TSDB_BE, table=table_to_delete)
460
- except v3io_frames.DeleteError as e:
458
+ if table_to_delete in self.tables:
459
+ try:
460
+ self.frames_client.delete(
461
+ backend=_TSDB_BE, table=self.tables[table_to_delete]
462
+ )
463
+ except v3io_frames.DeleteError as e:
464
+ logger.warning(
465
+ f"Failed to delete TSDB table '{table_to_delete}'",
466
+ err=mlrun.errors.err_to_str(e),
467
+ )
468
+ else:
461
469
  logger.warning(
462
- f"Failed to delete TSDB table '{table}'",
463
- err=mlrun.errors.err_to_str(e),
470
+ f"Skipping deletion: table '{table_to_delete}' is not among the initialized tables.",
471
+ initialized_tables=list(self.tables.keys()),
464
472
  )
465
473
 
466
474
  # Final cleanup of tsdb path
mlrun/projects/project.py CHANGED
@@ -30,6 +30,7 @@ from copy import deepcopy
30
30
  from os import environ, makedirs, path
31
31
  from typing import Callable, Optional, Union, cast
32
32
 
33
+ import deprecated
33
34
  import dotenv
34
35
  import git
35
36
  import git.exc
@@ -2860,6 +2861,20 @@ class MlrunProject(ModelObj):
2860
2861
 
2861
2862
  self.spec.set_function(name, function_object, func)
2862
2863
 
2864
+ # TODO: Remove this in 1.11.0
2865
+ @deprecated.deprecated(
2866
+ version="1.8.0",
2867
+ reason="'remove_function' is deprecated and will be removed in 1.11.0. "
2868
+ "Please use `delete_function` instead.",
2869
+ category=FutureWarning,
2870
+ )
2871
+ def remove_function(self, name):
2872
+ """remove the specified function from the project
2873
+
2874
+ :param name: name of the function (under the project)
2875
+ """
2876
+ self.spec.remove_function(name)
2877
+
2863
2878
  def delete_function(self, name, delete_from_db=False):
2864
2879
  """deletes the specified function from the project
2865
2880
 
@@ -3695,7 +3710,7 @@ class MlrunProject(ModelObj):
3695
3710
  brokers=["<kafka-broker-ip-address>:9094"],
3696
3711
  topics=[], # Keep the topics list empty
3697
3712
  ## SASL is supported
3698
- # sasl_user="user1",
3713
+ # sasl_user="<kafka-sasl-user>",
3699
3714
  # sasl_pass="<kafka-sasl-password>",
3700
3715
  )
3701
3716
  project.register_datastore_profile(stream_profile)
@@ -3728,6 +3743,29 @@ class MlrunProject(ModelObj):
3728
3743
 
3729
3744
  In the V3IO datastore, you must provide an explicit access key to the stream, but not to the TSDB.
3730
3745
 
3746
+ An external Confluent Kafka stream is also supported. Here is an example:
3747
+
3748
+ .. code-block:: python
3749
+
3750
+ from mlrun.datastore.datastore_profile import DatastoreProfileKafkaSource
3751
+
3752
+ stream_profile = DatastoreProfileKafkaSource(
3753
+ name="confluent-kafka",
3754
+ brokers=["<server-domain-start>.confluent.cloud:9092"],
3755
+ topics=[],
3756
+ sasl_user="<API-key>",
3757
+ sasl_pass="<API-secret>",
3758
+ kwargs_public={
3759
+ "security_protocol": "SASL_SSL",
3760
+ "api_version_auto_timeout_ms": 15_000, # 15 seconds
3761
+ "tls": {"enable": True},
3762
+ "new_topic": {"replication_factor": 3},
3763
+ },
3764
+ )
3765
+
3766
+ The replication factor and timeout configuration might need to be adjusted according to your Confluent cluster
3767
+ type and settings.
3768
+
3731
3769
  :param tsdb_profile_name: The datastore profile name of the time-series database to be used in model
3732
3770
  monitoring. The supported profiles are:
3733
3771
 
@@ -3781,7 +3819,7 @@ class MlrunProject(ModelObj):
3781
3819
  top_level: bool = False,
3782
3820
  uids: Optional[list[str]] = None,
3783
3821
  latest_only: bool = False,
3784
- tsdb_metrics: bool = True,
3822
+ tsdb_metrics: bool = False,
3785
3823
  metric_list: Optional[list[str]] = None,
3786
3824
  ) -> mlrun.common.schemas.ModelEndpointList:
3787
3825
  """
@@ -4003,8 +4041,10 @@ class MlrunProject(ModelObj):
4003
4041
  e.g. builder_env={"GIT_TOKEN": token}, does not work yet in KFP
4004
4042
  :param overwrite_build_params: Overwrite existing build configuration (currently applies to
4005
4043
  requirements and commands)
4044
+
4006
4045
  * False: The new params are merged with the existing
4007
4046
  * True: The existing params are replaced by the new ones
4047
+
4008
4048
  :param extra_args: A string containing additional builder arguments in the format of command-line options,
4009
4049
  e.g. extra_args="--skip-tls-verify --build-arg A=val"
4010
4050
  :param force_build: force building the image, even when no changes were made
@@ -4055,8 +4095,10 @@ class MlrunProject(ModelObj):
4055
4095
  :param requirements_file: requirements file to install on the built image
4056
4096
  :param overwrite_build_params: Overwrite existing build configuration (currently applies to
4057
4097
  requirements and commands)
4098
+
4058
4099
  * False: The new params are merged with the existing
4059
4100
  * True: The existing params are replaced by the new ones
4101
+
4060
4102
  :param builder_env: Kaniko builder pod env vars dict (for config/credentials)
4061
4103
  e.g. builder_env={"GIT_TOKEN": token}, does not work yet in KFP
4062
4104
  :param extra_args: A string containing additional builder arguments in the format of command-line options,
@@ -4128,8 +4170,10 @@ class MlrunProject(ModelObj):
4128
4170
  e.g. builder_env={"GIT_TOKEN": token}, does not work yet in KFP
4129
4171
  :param overwrite_build_params: Overwrite existing build configuration (currently applies to
4130
4172
  requirements and commands)
4173
+
4131
4174
  * False: The new params are merged with the existing
4132
4175
  * True: The existing params are replaced by the new ones
4176
+
4133
4177
  :param extra_args: A string containing additional builder arguments in the format of command-line options,
4134
4178
  e.g. extra_args="--skip-tls-verify --build-arg A=val"
4135
4179
  :param target_dir: Path on the image where source code would be extracted (by default `/home/mlrun_code`)
@@ -4307,12 +4351,14 @@ class MlrunProject(ModelObj):
4307
4351
  ``my_Name_1`` or ``surname``.
4308
4352
  :param tag: Return artifacts assigned this tag.
4309
4353
  :param labels: Filter artifacts by label key-value pairs or key existence. This can be provided as:
4310
- - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4311
- or `{"label": None}` to check for key existence.
4312
- - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4313
- or just `"label"` for key existence.
4314
- - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4315
- the specified key-value pairs or key existence.
4354
+
4355
+ - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4356
+ or `{"label": None}` to check for key existence.
4357
+ - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4358
+ or just `"label"` for key existence.
4359
+ - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4360
+ the specified key-value pairs or key existence.
4361
+
4316
4362
  :param since: Not in use in :py:class:`HTTPRunDB`.
4317
4363
  :param until: Not in use in :py:class:`HTTPRunDB`.
4318
4364
  :param iter: Return artifacts from a specific iteration (where ``iter=0`` means the root iteration). If
@@ -4323,7 +4369,7 @@ class MlrunProject(ModelObj):
4323
4369
  :param kind: Return artifacts of the requested kind.
4324
4370
  :param category: Return artifacts of the requested category.
4325
4371
  :param tree: Return artifacts of the requested tree.
4326
- :param limit: Maximum number of artifacts to return.
4372
+ :param limit: Deprecated - Maximum number of artifacts to return (will be removed in 1.11.0).
4327
4373
  :param format_: The format in which to return the artifacts. Default is 'full'.
4328
4374
  :param partition_by: Field to group results by. When `partition_by` is specified, the `partition_sort_by`
4329
4375
  parameter must be provided as well.
@@ -4334,6 +4380,14 @@ class MlrunProject(ModelObj):
4334
4380
  :param partition_order: Order of sorting within partitions - `asc` or `desc`. Default is `desc`.
4335
4381
  """
4336
4382
  db = mlrun.db.get_run_db(secrets=self._secrets)
4383
+
4384
+ if limit:
4385
+ # TODO: Remove this in 1.11.0
4386
+ warnings.warn(
4387
+ "'limit' is deprecated and will be removed in 1.11.0. Use 'page' and 'page_size' instead.",
4388
+ FutureWarning,
4389
+ )
4390
+
4337
4391
  return db.list_artifacts(
4338
4392
  name,
4339
4393
  self.metadata.name,
@@ -4446,12 +4500,14 @@ class MlrunProject(ModelObj):
4446
4500
  ``my_Name_1`` or ``surname``.
4447
4501
  :param tag: Return artifacts assigned this tag.
4448
4502
  :param labels: Filter model artifacts by label key-value pairs or key existence. This can be provided as:
4449
- - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4450
- or `{"label": None}` to check for key existence.
4451
- - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4452
- or just `"label"` for key existence.
4453
- - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4454
- the specified key-value pairs or key existence.
4503
+
4504
+ - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4505
+ or `{"label": None}` to check for key existence.
4506
+ - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4507
+ or just `"label"` for key existence.
4508
+ - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4509
+ the specified key-value pairs or key existence.
4510
+
4455
4511
  :param since: Not in use in :py:class:`HTTPRunDB`.
4456
4512
  :param until: Not in use in :py:class:`HTTPRunDB`.
4457
4513
  :param iter: Return artifacts from a specific iteration (where ``iter=0`` means the root iteration). If
@@ -4557,12 +4613,14 @@ class MlrunProject(ModelObj):
4557
4613
  :param name: Return only functions with a specific name.
4558
4614
  :param tag: Return function versions with specific tags. To return only tagged functions, set tag to ``"*"``.
4559
4615
  :param labels: Filter functions by label key-value pairs or key existence. This can be provided as:
4560
- - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4561
- or `{"label": None}` to check for key existence.
4562
- - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4563
- or just `"label"` for key existence.
4564
- - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4565
- the specified key-value pairs or key existence.
4616
+
4617
+ - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4618
+ or `{"label": None}` to check for key existence.
4619
+ - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4620
+ or just `"label"` for key existence.
4621
+ - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4622
+ the specified key-value pairs or key existence.
4623
+
4566
4624
  :param kind: Return functions of the specified kind. If not provided, all function kinds will be returned.
4567
4625
  :param format_: The format in which to return the functions. Default is 'full'.
4568
4626
  :returns: List of function objects.
@@ -4656,12 +4714,14 @@ class MlrunProject(ModelObj):
4656
4714
  :param name: Return only functions with a specific name.
4657
4715
  :param tag: Return function versions with specific tags.
4658
4716
  :param labels: Filter functions by label key-value pairs or key existence. This can be provided as:
4659
- - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4660
- or `{"label": None}` to check for key existence.
4661
- - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4662
- or just `"label"` for key existence.
4663
- - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4664
- the specified key-value pairs or key existence.
4717
+
4718
+ - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4719
+ or `{"label": None}` to check for key existence.
4720
+ - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4721
+ or just `"label"` for key existence.
4722
+ - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4723
+ the specified key-value pairs or key existence.
4724
+
4665
4725
  :returns: List of function objects.
4666
4726
  """
4667
4727
 
@@ -4717,12 +4777,14 @@ class MlrunProject(ModelObj):
4717
4777
  :param name: Name of the run to retrieve.
4718
4778
  :param uid: Unique ID of the run.
4719
4779
  :param labels: Filter runs by label key-value pairs or key existence. This can be provided as:
4720
- - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4721
- or `{"label": None}` to check for key existence.
4722
- - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4723
- or just `"label"` for key existence.
4724
- - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4725
- the specified key-value pairs or key existence.
4780
+
4781
+ - A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
4782
+ or `{"label": None}` to check for key existence.
4783
+ - A list of strings formatted as `"label=value"` to match specific label key-value pairs,
4784
+ or just `"label"` for key existence.
4785
+ - A comma-separated string formatted as `"label1=value1,label2"` to match entities with
4786
+ the specified key-value pairs or key existence.
4787
+
4726
4788
  :param state: Deprecated - List only runs whose state is specified.
4727
4789
  :param states: List only runs whose state is one of the provided states.
4728
4790
  :param sort: Whether to sort the result according to their start time. Otherwise, results will be
mlrun/render.py CHANGED
@@ -361,9 +361,6 @@ def get_tblframe(df, display, classes=None):
361
361
  return ipython_display(html, display)
362
362
 
363
363
 
364
- uid_template = '<div title="{}"><a href="{}/{}/{}/jobs/monitor/{}/overview" target="_blank" >...{}</a></div>'
365
-
366
-
367
364
  def runs_to_html(
368
365
  df: pd.DataFrame,
369
366
  display: bool = True,
@@ -379,15 +376,14 @@ def runs_to_html(
379
376
  df["results"] = df["results"].apply(dict_html)
380
377
  df["start"] = df["start"].apply(time_str)
381
378
  df["parameters"] = df["parameters"].apply(dict_html)
379
+ uid_template = '<div title="{}"><a href="{}" target="_blank" >...{}</a></div>'
380
+
382
381
  if config.resolve_ui_url():
383
382
  df["uid"] = df.apply(
384
383
  lambda x: uid_template.format(
385
- x.uid,
386
- config.resolve_ui_url(),
387
- config.ui.projects_prefix,
388
- x.project,
389
- x.uid,
390
- x.uid[-8:],
384
+ x["uid"],
385
+ mlrun.utils.get_run_url(x["project"], x["uid"], x["name"]),
386
+ x["uid"][-8:],
391
387
  ),
392
388
  axis=1,
393
389
  )
mlrun/runtimes/base.py CHANGED
@@ -499,7 +499,7 @@ class BaseRuntime(ModelObj):
499
499
  def _store_function(self, runspec, meta, db):
500
500
  meta.labels["kind"] = self.kind
501
501
  mlrun.runtimes.utils.enrich_run_labels(
502
- meta.labels, [mlrun.common.runtimes.constants.RunLabels.owner]
502
+ meta.labels, [mlrun_constants.MLRunInternalLabels.owner]
503
503
  )
504
504
  if runspec.spec.output_path:
505
505
  runspec.spec.output_path = runspec.spec.output_path.replace(
mlrun/runtimes/utils.py CHANGED
@@ -11,6 +11,7 @@
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
+ import enum
14
15
  import getpass
15
16
  import hashlib
16
17
  import json
@@ -28,7 +29,6 @@ import mlrun.common.constants as mlrun_constants
28
29
  import mlrun.common.schemas
29
30
  import mlrun.utils.regex
30
31
  from mlrun.artifacts import TableArtifact
31
- from mlrun.common.runtimes.constants import RunLabels
32
32
  from mlrun.config import config
33
33
  from mlrun.errors import err_to_str
34
34
  from mlrun.frameworks.parallel_coordinates import gen_pcp_plot
@@ -433,18 +433,35 @@ def enrich_function_from_dict(function, function_dict):
433
433
 
434
434
  def enrich_run_labels(
435
435
  labels: dict,
436
- labels_to_enrich: Optional[list[RunLabels]] = None,
436
+ labels_to_enrich: Optional[list[mlrun_constants.MLRunInternalLabels]] = None,
437
437
  ):
438
+ """
439
+ Enrich the run labels with the internal labels and the labels enrichment extension
440
+ :param labels: The run labels dict
441
+ :param labels_to_enrich: The label keys to enrich from MLRunInternalLabels.default_run_labels_to_enrich
442
+ :return: The enriched labels dict
443
+ """
444
+ # Merge the labels with the labels enrichment extension
438
445
  labels_enrichment = {
439
- RunLabels.owner: os.environ.get("V3IO_USERNAME") or getpass.getuser(),
440
- # TODO: remove this in 1.9.0
441
- RunLabels.v3io_user: os.environ.get("V3IO_USERNAME"),
446
+ mlrun_constants.MLRunInternalLabels.owner: os.environ.get("V3IO_USERNAME")
447
+ or getpass.getuser(),
448
+ # TODO: remove this in 1.10.0
449
+ mlrun_constants.MLRunInternalLabels.v3io_user: os.environ.get("V3IO_USERNAME"),
442
450
  }
443
- labels_to_enrich = labels_to_enrich or RunLabels.all()
451
+
452
+ # Resolve which label keys to enrich
453
+ if labels_to_enrich is None:
454
+ labels_to_enrich = (
455
+ mlrun_constants.MLRunInternalLabels.default_run_labels_to_enrich()
456
+ )
457
+
458
+ # Enrich labels
444
459
  for label in labels_to_enrich:
460
+ if isinstance(label, enum.Enum):
461
+ label = label.value
445
462
  enrichment = labels_enrichment.get(label)
446
- if label.value not in labels and enrichment:
447
- labels[label.value] = enrichment
463
+ if label not in labels and enrichment:
464
+ labels[label] = enrichment
448
465
  return labels
449
466
 
450
467