mlrun 1.7.0rc42__py3-none-any.whl → 1.7.0rc44__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.

Files changed (50) hide show
  1. mlrun/__main__.py +4 -2
  2. mlrun/artifacts/base.py +1 -1
  3. mlrun/artifacts/manager.py +15 -4
  4. mlrun/common/schemas/__init__.py +1 -0
  5. mlrun/common/schemas/alert.py +11 -11
  6. mlrun/common/schemas/client_spec.py +0 -1
  7. mlrun/common/schemas/frontend_spec.py +7 -0
  8. mlrun/common/schemas/notification.py +32 -5
  9. mlrun/common/schemas/workflow.py +1 -0
  10. mlrun/config.py +46 -21
  11. mlrun/data_types/data_types.py +5 -0
  12. mlrun/datastore/base.py +4 -7
  13. mlrun/datastore/storeytargets.py +4 -3
  14. mlrun/datastore/targets.py +17 -4
  15. mlrun/db/httpdb.py +2 -12
  16. mlrun/db/nopdb.py +21 -4
  17. mlrun/execution.py +7 -2
  18. mlrun/feature_store/api.py +1 -0
  19. mlrun/feature_store/retrieval/spark_merger.py +7 -3
  20. mlrun/frameworks/_common/plan.py +3 -3
  21. mlrun/frameworks/_ml_common/plan.py +1 -1
  22. mlrun/frameworks/parallel_coordinates.py +2 -3
  23. mlrun/k8s_utils.py +48 -2
  24. mlrun/launcher/client.py +6 -6
  25. mlrun/model.py +2 -1
  26. mlrun/model_monitoring/controller.py +1 -1
  27. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +15 -1
  28. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +12 -0
  29. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +2 -2
  30. mlrun/model_monitoring/helpers.py +7 -15
  31. mlrun/model_monitoring/writer.py +8 -2
  32. mlrun/projects/pipelines.py +2 -0
  33. mlrun/projects/project.py +146 -57
  34. mlrun/render.py +3 -3
  35. mlrun/runtimes/kubejob.py +6 -6
  36. mlrun/runtimes/local.py +4 -1
  37. mlrun/runtimes/nuclio/api_gateway.py +6 -0
  38. mlrun/runtimes/nuclio/application/application.py +3 -2
  39. mlrun/runtimes/pod.py +16 -8
  40. mlrun/runtimes/sparkjob/spark3job.py +4 -0
  41. mlrun/utils/async_http.py +1 -1
  42. mlrun/utils/helpers.py +56 -22
  43. mlrun/utils/notifications/notification/__init__.py +0 -1
  44. mlrun/utils/version/version.json +2 -2
  45. {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc44.dist-info}/METADATA +27 -27
  46. {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc44.dist-info}/RECORD +50 -50
  47. {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc44.dist-info}/WHEEL +1 -1
  48. {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc44.dist-info}/LICENSE +0 -0
  49. {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc44.dist-info}/entry_points.txt +0 -0
  50. {mlrun-1.7.0rc42.dist-info → mlrun-1.7.0rc44.dist-info}/top_level.txt +0 -0
mlrun/__main__.py CHANGED
@@ -734,9 +734,11 @@ def get(kind, name, selector, namespace, uid, project, tag, db, extra_args):
734
734
  if db:
735
735
  mlconf.dbpath = db
736
736
  if not project:
737
- print("Warning, project parameter was not specified using default !")
737
+ logger.warning(
738
+ "Project parameter was not specified. Defaulting to 'default' project"
739
+ )
738
740
  if kind.startswith("po"):
739
- print("Unsupported, use 'get runtimes' instead")
741
+ logger.warning("Unsupported, use 'get runtimes' instead")
740
742
  return
741
743
 
742
744
  elif kind.startswith("runtime"):
mlrun/artifacts/base.py CHANGED
@@ -159,7 +159,7 @@ class ArtifactSpec(ModelObj):
159
159
  self._is_inline = True
160
160
 
161
161
  def get_body(self):
162
- """get the artifact body when inline"""
162
+ """Get the artifact body"""
163
163
  return self._body
164
164
 
165
165
 
@@ -23,7 +23,7 @@ import mlrun.utils.regex
23
23
  from mlrun.utils.helpers import (
24
24
  get_local_file_schema,
25
25
  template_artifact_path,
26
- validate_inline_artifact_body_size,
26
+ validate_artifact_body_size,
27
27
  )
28
28
 
29
29
  from ..utils import (
@@ -72,7 +72,12 @@ class ArtifactProducer:
72
72
  self.inputs = {}
73
73
 
74
74
  def get_meta(self) -> dict:
75
- return {"kind": self.kind, "name": self.name, "tag": self.tag}
75
+ return {
76
+ "kind": self.kind,
77
+ "name": self.name,
78
+ "tag": self.tag,
79
+ "owner": self.owner,
80
+ }
76
81
 
77
82
  @property
78
83
  def uid(self):
@@ -195,7 +200,9 @@ class ArtifactManager:
195
200
  :param artifact_path: The path to store the artifact.
196
201
  If not provided, the artifact will be stored in the default artifact path.
197
202
  :param format: The format of the artifact. (e.g. csv, json, html, etc.)
198
- :param upload: Whether to upload the artifact or not.
203
+ :param upload: Whether to upload the artifact to the datastore. If not provided, and the
204
+ `local_path` is not a directory, upload occurs by default. Directories are uploaded only when this
205
+ flag is explicitly set to `True`.
199
206
  :param labels: Labels to add to the artifact.
200
207
  :param db_key: The key to use when logging the artifact to the DB.
201
208
  If not provided, will generate a key based on the producer name and the artifact key.
@@ -216,7 +223,11 @@ class ArtifactManager:
216
223
  target_path = target_path or item.target_path
217
224
 
218
225
  validate_artifact_key_name(key, "artifact.key")
219
- validate_inline_artifact_body_size(item.spec.inline)
226
+
227
+ # TODO: Create a tmp file, write the body to it, and use it as `local_path` instead of validating the body size.
228
+ validate_artifact_body_size(
229
+ body=item.spec.get_body(), is_inline=item.is_inline()
230
+ )
220
231
  src_path = local_path or item.src_path # TODO: remove src_path
221
232
  self.ensure_artifact_source_file_exists(item=item, path=src_path, body=body)
222
233
  if format == "html" or (src_path and pathlib.Path(src_path).suffix == "html"):
@@ -108,6 +108,7 @@ from .feature_store import (
108
108
  FeatureVectorsTagsOutput,
109
109
  )
110
110
  from .frontend_spec import (
111
+ ArtifactLimits,
111
112
  AuthenticationFeatureFlag,
112
113
  FeatureFlags,
113
114
  FrontendSpec,
@@ -34,17 +34,17 @@ class EventEntities(pydantic.BaseModel):
34
34
 
35
35
 
36
36
  class EventKind(StrEnum):
37
- DATA_DRIFT_DETECTED = "data_drift_detected"
38
- DATA_DRIFT_SUSPECTED = "data_drift_suspected"
39
- CONCEPT_DRIFT_DETECTED = "concept_drift_detected"
40
- CONCEPT_DRIFT_SUSPECTED = "concept_drift_suspected"
41
- MODEL_PERFORMANCE_DETECTED = "model_performance_detected"
42
- MODEL_PERFORMANCE_SUSPECTED = "model_performance_suspected"
43
- SYSTEM_PERFORMANCE_DETECTED = "system_performance_detected"
44
- SYSTEM_PERFORMANCE_SUSPECTED = "system_performance_suspected"
45
- MM_APP_ANOMALY_DETECTED = "mm_app_anomaly_detected"
46
- MM_APP_ANOMALY_SUSPECTED = "mm_app_anomaly_suspected"
47
- MM_APP_FAILED = "mm_app_failed"
37
+ DATA_DRIFT_DETECTED = "data-drift-detected"
38
+ DATA_DRIFT_SUSPECTED = "data-drift-suspected"
39
+ CONCEPT_DRIFT_DETECTED = "concept-drift-detected"
40
+ CONCEPT_DRIFT_SUSPECTED = "concept-drift-suspected"
41
+ MODEL_PERFORMANCE_DETECTED = "model-performance-detected"
42
+ MODEL_PERFORMANCE_SUSPECTED = "model-performance-suspected"
43
+ SYSTEM_PERFORMANCE_DETECTED = "system-performance-detected"
44
+ SYSTEM_PERFORMANCE_SUSPECTED = "system-performance-suspected"
45
+ MM_APP_ANOMALY_DETECTED = "mm-app-anomaly-detected"
46
+ MM_APP_ANOMALY_SUSPECTED = "mm-app-anomaly-suspected"
47
+ MM_APP_FAILED = "mm-app-failed"
48
48
  FAILED = "failed"
49
49
 
50
50
 
@@ -57,7 +57,6 @@ class ClientSpec(pydantic.BaseModel):
57
57
  redis_url: typing.Optional[str]
58
58
  redis_type: typing.Optional[str]
59
59
  sql_url: typing.Optional[str]
60
- model_endpoint_monitoring_store_type: typing.Optional[str]
61
60
  model_endpoint_monitoring_endpoint_store_connection: typing.Optional[str]
62
61
  model_monitoring_tsdb_connection: typing.Optional[str]
63
62
  ce: typing.Optional[dict]
@@ -50,6 +50,12 @@ class FeatureFlags(pydantic.BaseModel):
50
50
  preemption_nodes: PreemptionNodesFeatureFlag
51
51
 
52
52
 
53
+ class ArtifactLimits(pydantic.BaseModel):
54
+ max_chunk_size: int
55
+ max_preview_size: int
56
+ max_download_size: int
57
+
58
+
53
59
  class FrontendSpec(pydantic.BaseModel):
54
60
  jobs_dashboard_url: typing.Optional[str]
55
61
  model_monitoring_dashboard_url: typing.Optional[str]
@@ -71,3 +77,4 @@ class FrontendSpec(pydantic.BaseModel):
71
77
  allowed_artifact_path_prefixes_list: list[str]
72
78
  ce: typing.Optional[dict]
73
79
  internal_labels: list[str] = []
80
+ artifact_limits: ArtifactLimits
@@ -22,11 +22,38 @@ import mlrun.common.types
22
22
 
23
23
 
24
24
  class NotificationKind(mlrun.common.types.StrEnum):
25
- console = "console"
26
- git = "git"
27
- ipython = "ipython"
28
- slack = "slack"
29
- webhook = "webhook"
25
+ """Currently, the supported notification kinds and their params are as follows:"""
26
+
27
+ console: str = "console"
28
+ """no params, local only"""
29
+
30
+ git: str = "git"
31
+ """
32
+ **token** - The git token to use for the git notification.\n
33
+ **repo** - The git repo to which to send the notification.\n
34
+ **issue** - The git issue to which to send the notification.\n
35
+ **merge_request** -
36
+ In GitLab (as opposed to GitHub), merge requests and issues are separate entities.
37
+ If using merge request, the issue will be ignored, and vice versa.\n
38
+ **server** - The git server to which to send the notification.\n
39
+ **gitlab** - (bool) Whether the git server is GitLab or not.\n
40
+ """
41
+
42
+ ipython: str = "ipython"
43
+ """no params, local only"""
44
+
45
+ slack: str = "slack"
46
+ """**webhook** - The slack webhook to which to send the notification."""
47
+
48
+ webhook: str = "webhook"
49
+ """
50
+ **url** - The webhook url to which to send the notification.\n
51
+ **method** - The http method to use when sending the notification (GET, POST, PUT, etc…).\n
52
+ **headers** - (dict) The http headers to send with the notification.\n
53
+ **override_body** - (dict) The body to send with the notification.\n
54
+ **verify_ssl** -
55
+ (bool) Whether SSL certificates are validated during HTTP requests or not, The default is set to True.
56
+ """
30
57
 
31
58
 
32
59
  class NotificationSeverity(mlrun.common.types.StrEnum):
@@ -32,6 +32,7 @@ class WorkflowSpec(pydantic.BaseModel):
32
32
  schedule: typing.Union[str, ScheduleCronTrigger] = None
33
33
  run_local: typing.Optional[bool] = None
34
34
  image: typing.Optional[str] = None
35
+ workflow_runner_node_selector: typing.Optional[dict[str, str]] = None
35
36
 
36
37
 
37
38
  class WorkflowRequest(pydantic.BaseModel):
mlrun/config.py CHANGED
@@ -27,6 +27,7 @@ import copy
27
27
  import json
28
28
  import os
29
29
  import typing
30
+ import warnings
30
31
  from collections.abc import Mapping
31
32
  from datetime import timedelta
32
33
  from distutils.util import strtobool
@@ -35,6 +36,7 @@ from threading import Lock
35
36
 
36
37
  import dotenv
37
38
  import semver
39
+ import urllib3.exceptions
38
40
  import yaml
39
41
 
40
42
  import mlrun.common.constants
@@ -152,6 +154,11 @@ default_config = {
152
154
  "datasets": {
153
155
  "max_preview_columns": 100,
154
156
  },
157
+ "limits": {
158
+ "max_chunk_size": 1024 * 1024 * 1, # 1MB
159
+ "max_preview_size": 1024 * 1024 * 10, # 10MB
160
+ "max_download_size": 1024 * 1024 * 100, # 100MB
161
+ },
155
162
  },
156
163
  # FIXME: Adding these defaults here so we won't need to patch the "installing component" (provazio-controller) to
157
164
  # configure this values on field systems, for newer system this will be configured correctly
@@ -326,7 +333,7 @@ default_config = {
326
333
  "http": {
327
334
  # when True, the client will verify the server's TLS
328
335
  # set to False for backwards compatibility.
329
- "verify": False,
336
+ "verify": True,
330
337
  },
331
338
  "db": {
332
339
  "commit_retry_timeout": 30,
@@ -532,7 +539,6 @@ default_config = {
532
539
  "store_prefixes": {
533
540
  "default": "v3io:///users/pipelines/{project}/model-endpoints/{kind}",
534
541
  "user_space": "v3io:///projects/{project}/model-endpoints/{kind}",
535
- "stream": "", # TODO: Delete in 1.9.0
536
542
  "monitoring_application": "v3io:///users/pipelines/{project}/monitoring-apps/",
537
543
  },
538
544
  # Offline storage path can be either relative or a full path. This path is used for general offline data
@@ -545,7 +551,6 @@ default_config = {
545
551
  "parquet_batching_max_events": 10_000,
546
552
  "parquet_batching_timeout_secs": timedelta(minutes=1).total_seconds(),
547
553
  # See mlrun.model_monitoring.db.stores.ObjectStoreFactory for available options
548
- "store_type": "v3io-nosql", # TODO: Delete in 1.9.0
549
554
  "endpoint_store_connection": "",
550
555
  # See mlrun.model_monitoring.db.tsdb.ObjectTSDBFactory for available options
551
556
  "tsdb_connection": "",
@@ -791,7 +796,21 @@ class Config:
791
796
  for key, value in cfg.items():
792
797
  if hasattr(self, key):
793
798
  if isinstance(value, dict):
794
- getattr(self, key).update(value)
799
+ # ignore the `skip_errors` flag here
800
+ # if the key does not align with what mlrun config expects it is a user
801
+ # input error that can lead to unexpected behavior.
802
+ # raise the exception to ensure configuration is loaded correctly and do not
803
+ # ignore any errors.
804
+ config_value = getattr(self, key)
805
+ try:
806
+ config_value.update(value)
807
+ except AttributeError as exc:
808
+ if not isinstance(config_value, (dict, Config)):
809
+ raise ValueError(
810
+ f"Can not update `{key}` config. "
811
+ f"Expected a configuration but received {type(value)}"
812
+ ) from exc
813
+ raise exc
795
814
  else:
796
815
  try:
797
816
  setattr(self, key, value)
@@ -1095,6 +1114,9 @@ class Config:
1095
1114
  # importing here to avoid circular dependency
1096
1115
  import mlrun.db
1097
1116
 
1117
+ # It ensures that SSL verification is set before establishing a connection
1118
+ _configure_ssl_verification(self.httpdb.http.verify)
1119
+
1098
1120
  # when dbpath is set we want to connect to it which will sync configuration from it to the client
1099
1121
  mlrun.db.get_run_db(value, force_reconnect=True)
1100
1122
 
@@ -1123,10 +1145,10 @@ class Config:
1123
1145
  project: str = "",
1124
1146
  kind: str = "",
1125
1147
  target: str = "online",
1126
- artifact_path: str = None,
1127
- function_name: str = None,
1148
+ artifact_path: typing.Optional[str] = None,
1149
+ function_name: typing.Optional[str] = None,
1128
1150
  **kwargs,
1129
- ) -> typing.Union[str, list[str]]:
1151
+ ) -> str:
1130
1152
  """Get the full path from the configuration based on the provided project and kind.
1131
1153
 
1132
1154
  :param project: Project name.
@@ -1142,8 +1164,7 @@ class Config:
1142
1164
  relative artifact path will be taken from the global MLRun artifact path.
1143
1165
  :param function_name: Application name, None for model_monitoring_stream.
1144
1166
 
1145
- :return: Full configured path for the provided kind. Can be either a single path
1146
- or a list of paths in the case of the online model monitoring stream path.
1167
+ :return: Full configured path for the provided kind.
1147
1168
  """
1148
1169
 
1149
1170
  if target != "offline":
@@ -1164,18 +1185,11 @@ class Config:
1164
1185
  if function_name is None
1165
1186
  else f"{kind}-{function_name.lower()}",
1166
1187
  )
1167
- elif kind == "stream": # return list for mlrun<1.6.3 BC
1168
- return [
1169
- # TODO: remove the first stream in 1.9.0
1170
- mlrun.mlconf.model_endpoint_monitoring.store_prefixes.default.format(
1171
- project=project,
1172
- kind=kind,
1173
- ), # old stream uri (pipelines) for BC ML-6043
1174
- mlrun.mlconf.model_endpoint_monitoring.store_prefixes.user_space.format(
1175
- project=project,
1176
- kind=kind,
1177
- ), # new stream uri (projects)
1178
- ]
1188
+ elif kind == "stream":
1189
+ return mlrun.mlconf.model_endpoint_monitoring.store_prefixes.user_space.format(
1190
+ project=project,
1191
+ kind=kind,
1192
+ )
1179
1193
  else:
1180
1194
  return mlrun.mlconf.model_endpoint_monitoring.store_prefixes.default.format(
1181
1195
  project=project,
@@ -1292,6 +1306,7 @@ def _do_populate(env=None, skip_errors=False):
1292
1306
  if data:
1293
1307
  config.update(data, skip_errors=skip_errors)
1294
1308
 
1309
+ _configure_ssl_verification(config.httpdb.http.verify)
1295
1310
  _validate_config(config)
1296
1311
 
1297
1312
 
@@ -1351,6 +1366,16 @@ def _convert_str(value, typ):
1351
1366
  return typ(value)
1352
1367
 
1353
1368
 
1369
+ def _configure_ssl_verification(verify_ssl: bool) -> None:
1370
+ """Configure SSL verification warnings based on the setting."""
1371
+ if not verify_ssl:
1372
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
1373
+ else:
1374
+ # If the user changes the `verify` setting to `True` at runtime using `mlrun.set_env_from_file` after
1375
+ # importing `mlrun`, we need to reload the `mlrun` configuration and enable this warning.
1376
+ warnings.simplefilter("default", urllib3.exceptions.InsecureRequestWarning)
1377
+
1378
+
1354
1379
  def read_env(env=None, prefix=env_prefix):
1355
1380
  """Read configuration from environment"""
1356
1381
  env = os.environ if env is None else env
@@ -70,6 +70,11 @@ def pa_type_to_value_type(type_):
70
70
  if isinstance(type_, TimestampType):
71
71
  return ValueType.DATETIME
72
72
 
73
+ # pandas category type translates to pyarrow DictionaryType
74
+ # we need to unpack the value type (ML-7868)
75
+ if isinstance(type_, pyarrow.DictionaryType):
76
+ type_ = type_.value_type
77
+
73
78
  type_map = {
74
79
  pyarrow.bool_(): ValueType.BOOL,
75
80
  pyarrow.int64(): ValueType.INT64,
mlrun/datastore/base.py CHANGED
@@ -24,13 +24,12 @@ import pandas as pd
24
24
  import pyarrow
25
25
  import pytz
26
26
  import requests
27
- import urllib3
28
27
  from deprecated import deprecated
29
28
 
30
29
  import mlrun.config
31
30
  import mlrun.errors
32
31
  from mlrun.errors import err_to_str
33
- from mlrun.utils import StorePrefix, is_ipython, logger
32
+ from mlrun.utils import StorePrefix, is_jupyter, logger
34
33
 
35
34
  from .store_resources import is_store_uri, parse_store_uri
36
35
  from .utils import filter_df_start_end_time, select_columns_from_df
@@ -620,14 +619,14 @@ class DataItem:
620
619
  )
621
620
  return df
622
621
 
623
- def show(self, format=None):
622
+ def show(self, format: Optional[str] = None) -> None:
624
623
  """show the data object content in Jupyter
625
624
 
626
625
  :param format: format to use (when there is no/wrong suffix), e.g. 'png'
627
626
  """
628
- if not is_ipython:
627
+ if not is_jupyter:
629
628
  logger.warning(
630
- "Jupyter/IPython was not detected, .show() will only display inside Jupyter"
629
+ "Jupyter was not detected. `.show()` displays only inside Jupyter."
631
630
  )
632
631
  return
633
632
 
@@ -745,8 +744,6 @@ class HttpStore(DataStore):
745
744
 
746
745
  verify_ssl = mlconf.httpdb.http.verify
747
746
  try:
748
- if not verify_ssl:
749
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
750
747
  response = requests.get(url, headers=headers, auth=auth, verify=verify_ssl)
751
748
  except OSError as exc:
752
749
  raise OSError(f"error: cannot connect to {url}: {err_to_str(exc)}")
@@ -89,8 +89,8 @@ class StreamStoreyTarget(storey.StreamTarget):
89
89
  raise mlrun.errors.MLRunInvalidArgumentError("StreamTarget requires a path")
90
90
 
91
91
  access_key = storage_options.get("v3io_access_key")
92
- storage = (
93
- V3ioDriver(webapi=endpoint or mlrun.mlconf.v3io_api, access_key=access_key),
92
+ storage = V3ioDriver(
93
+ webapi=endpoint or mlrun.mlconf.v3io_api, access_key=access_key
94
94
  )
95
95
 
96
96
  if storage_options:
@@ -137,7 +137,8 @@ class RedisNoSqlStoreyTarget(storey.NoSqlTarget):
137
137
  def __init__(self, *args, **kwargs):
138
138
  path = kwargs.pop("path")
139
139
  endpoint, uri = mlrun.datastore.targets.RedisNoSqlTarget.get_server_endpoint(
140
- path
140
+ path,
141
+ kwargs.pop("credentials_prefix", None),
141
142
  )
142
143
  kwargs["path"] = endpoint + "/" + uri
143
144
  super().__init__(*args, **kwargs)
@@ -439,6 +439,12 @@ class BaseStoreTarget(DataTargetBase):
439
439
  self.storage_options = storage_options
440
440
  self.schema = schema or {}
441
441
  self.credentials_prefix = credentials_prefix
442
+ if credentials_prefix:
443
+ warnings.warn(
444
+ "The 'credentials_prefix' parameter is deprecated and will be removed in "
445
+ "1.9.0. Please use datastore profiles instead.",
446
+ FutureWarning,
447
+ )
442
448
 
443
449
  self._target = None
444
450
  self._resource = None
@@ -1479,7 +1485,7 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
1479
1485
  writer_step_name = "RedisNoSqlTarget"
1480
1486
 
1481
1487
  @staticmethod
1482
- def get_server_endpoint(path):
1488
+ def get_server_endpoint(path, credentials_prefix=None):
1483
1489
  endpoint, uri = parse_path(path)
1484
1490
  endpoint = endpoint or mlrun.mlconf.redis.url
1485
1491
  if endpoint.startswith("ds://"):
@@ -1497,7 +1503,9 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
1497
1503
  raise mlrun.errors.MLRunInvalidArgumentError(
1498
1504
  "Provide Redis username and password only via secrets"
1499
1505
  )
1500
- credentials_prefix = mlrun.get_secret_or_env(key="CREDENTIALS_PREFIX")
1506
+ credentials_prefix = credentials_prefix or mlrun.get_secret_or_env(
1507
+ key="CREDENTIALS_PREFIX"
1508
+ )
1501
1509
  user = mlrun.get_secret_or_env(
1502
1510
  "REDIS_USER", default="", prefix=credentials_prefix
1503
1511
  )
@@ -1517,7 +1525,9 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
1517
1525
  from storey import Table
1518
1526
  from storey.redis_driver import RedisDriver
1519
1527
 
1520
- endpoint, uri = self.get_server_endpoint(self.get_target_path())
1528
+ endpoint, uri = self.get_server_endpoint(
1529
+ self.get_target_path(), self.credentials_prefix
1530
+ )
1521
1531
 
1522
1532
  return Table(
1523
1533
  uri,
@@ -1526,7 +1536,9 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
1526
1536
  )
1527
1537
 
1528
1538
  def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
1529
- endpoint, uri = self.get_server_endpoint(self.get_target_path())
1539
+ endpoint, uri = self.get_server_endpoint(
1540
+ self.get_target_path(), self.credentials_prefix
1541
+ )
1530
1542
  parsed_endpoint = urlparse(endpoint)
1531
1543
  store, path_in_store, path = self._get_store_and_path()
1532
1544
  return {
@@ -1577,6 +1589,7 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
1577
1589
  class_name="mlrun.datastore.storeytargets.RedisNoSqlStoreyTarget",
1578
1590
  columns=column_list,
1579
1591
  table=table,
1592
+ credentials_prefix=self.credentials_prefix,
1580
1593
  **self.attributes,
1581
1594
  )
1582
1595
 
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
@@ -1374,20 +1370,14 @@ class HTTPRunDB(RunDBInterface):
1374
1370
  :returns: :py:class:`~mlrun.common.schemas.GroupedByProjectRuntimeResourcesOutput` listing the runtime resources
1375
1371
  that were removed.
1376
1372
  """
1377
- if grace_period is None:
1378
- grace_period = config.runtime_resources_deletion_grace_period
1379
- logger.info(
1380
- "Using default grace period for runtime resources deletion",
1381
- grace_period=grace_period,
1382
- )
1383
-
1384
1373
  params = {
1385
1374
  "label-selector": label_selector,
1386
1375
  "kind": kind,
1387
1376
  "object-id": object_id,
1388
1377
  "force": force,
1389
- "grace-period": grace_period,
1390
1378
  }
1379
+ if grace_period is not None:
1380
+ params["grace-period"] = grace_period
1391
1381
  error = "Failed deleting runtime resources"
1392
1382
  project_path = project if project else "*"
1393
1383
  response = self.api_call(
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
- pass
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
- pass
169
+ return mlrun.lists.ArtifactList()
153
170
 
154
171
  def del_artifact(
155
172
  self,
@@ -181,7 +198,7 @@ class NopDB(RunDBInterface):
181
198
  def list_functions(
182
199
  self, name=None, project="", tag="", labels=None, since=None, until=None
183
200
  ):
184
- pass
201
+ return []
185
202
 
186
203
  def tag_objects(
187
204
  self,
@@ -421,7 +438,7 @@ class NopDB(RunDBInterface):
421
438
  ] = mlrun.common.formatters.PipelineFormat.metadata_only,
422
439
  page_size: int = None,
423
440
  ) -> mlrun.common.schemas.PipelinesOutput:
424
- pass
441
+ return mlrun.common.schemas.PipelinesOutput(runs=[], total_size=0)
425
442
 
426
443
  def create_project_secrets(
427
444
  self,
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
@@ -168,6 +169,8 @@ class MLClientCtx:
168
169
  @log_level.setter
169
170
  def log_level(self, value: str):
170
171
  """Set the logging level, e.g. 'debug', 'info', 'error'"""
172
+ level = logging.getLevelName(value.upper())
173
+ self._logger.set_logger_level(level)
171
174
  self._log_level = value
172
175
 
173
176
  @property
@@ -335,7 +338,7 @@ class MLClientCtx:
335
338
  "name": self.name,
336
339
  "kind": "run",
337
340
  "uri": uri,
338
- "owner": get_in(self._labels, "owner"),
341
+ "owner": get_in(self._labels, mlrun_constants.MLRunInternalLabels.owner),
339
342
  }
340
343
  if mlrun_constants.MLRunInternalLabels.workflow in self._labels:
341
344
  resp[mlrun_constants.MLRunInternalLabels.workflow] = self._labels[
@@ -631,7 +634,9 @@ class MLClientCtx:
631
634
  :param viewer: Kubeflow viewer type
632
635
  :param target_path: Absolute target path (instead of using artifact_path + local_path)
633
636
  :param src_path: Deprecated, use local_path
634
- :param upload: Upload to datastore (default is True)
637
+ :param upload: Whether to upload the artifact to the datastore. If not provided, and the `local_path`
638
+ is not a directory, upload occurs by default. Directories are uploaded only when this
639
+ flag is explicitly set to `True`.
635
640
  :param labels: A set of key/value labels to tag the artifact with
636
641
  :param format: Optional, format to use (e.g. csv, parquet, ..)
637
642
  :param db_key: The key to use in the artifact DB table, by default its run name + '_' + key
@@ -1051,6 +1051,7 @@ def _ingest_with_spark(
1051
1051
 
1052
1052
  spark = (
1053
1053
  pyspark.sql.SparkSession.builder.appName(session_name)
1054
+ .config("spark.driver.memory", "2g")
1054
1055
  .config("spark.sql.session.timeZone", "UTC")
1055
1056
  .getOrCreate()
1056
1057
  )
@@ -188,9 +188,13 @@ class SparkFeatureMerger(BaseMerger):
188
188
 
189
189
  if self.spark is None:
190
190
  # create spark context
191
- self.spark = SparkSession.builder.appName(
192
- f"vector-merger-{self.vector.metadata.name}"
193
- ).getOrCreate()
191
+ self.spark = (
192
+ SparkSession.builder.appName(
193
+ f"vector-merger-{self.vector.metadata.name}"
194
+ )
195
+ .config("spark.driver.memory", "2g")
196
+ .getOrCreate()
197
+ )
194
198
 
195
199
  def _get_engine_df(
196
200
  self,