mlrun 1.6.3rc3__py3-none-any.whl → 1.6.4rc2__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/config.py CHANGED
@@ -672,6 +672,10 @@ default_config = {
672
672
  "access_key": "",
673
673
  },
674
674
  "grafana_url": "",
675
+ "auth_with_client_id": {
676
+ "enabled": False,
677
+ "request_timeout": 5,
678
+ },
675
679
  }
676
680
 
677
681
  _is_running_as_api = None
@@ -1372,10 +1376,14 @@ def read_env(env=None, prefix=env_prefix):
1372
1376
  if log_formatter_name := config.get("log_formatter"):
1373
1377
  import mlrun.utils.logger
1374
1378
 
1375
- log_formatter = mlrun.utils.create_formatter_instance(
1379
+ log_formatter = mlrun.utils.resolve_formatter_by_kind(
1376
1380
  mlrun.utils.FormatterKinds(log_formatter_name)
1377
1381
  )
1378
- mlrun.utils.logger.get_handler("default").setFormatter(log_formatter)
1382
+ current_handler = mlrun.utils.logger.get_handler("default")
1383
+ current_formatter_name = current_handler.formatter.__class__.__name__
1384
+ desired_formatter_name = log_formatter.__name__
1385
+ if current_formatter_name != desired_formatter_name:
1386
+ current_handler.setFormatter(log_formatter())
1379
1387
 
1380
1388
  # The default function pod resource values are of type str; however, when reading from environment variable numbers,
1381
1389
  # it converts them to type int if contains only number, so we want to convert them to str.
mlrun/datastore/v3io.py CHANGED
@@ -12,8 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import mmap
16
- import os
17
15
  import time
18
16
  from datetime import datetime
19
17
 
@@ -22,7 +20,6 @@ import v3io
22
20
  from v3io.dataplane.response import HttpResponseError
23
21
 
24
22
  import mlrun
25
- from mlrun.datastore.helpers import ONE_GB, ONE_MB
26
23
 
27
24
  from ..platforms.iguazio import parse_path, split_path
28
25
  from .base import (
@@ -32,6 +29,7 @@ from .base import (
32
29
  )
33
30
 
34
31
  V3IO_LOCAL_ROOT = "v3io"
32
+ V3IO_DEFAULT_UPLOAD_CHUNK_SIZE = 1024 * 1024 * 100
35
33
 
36
34
 
37
35
  class V3ioStore(DataStore):
@@ -94,46 +92,28 @@ class V3ioStore(DataStore):
94
92
  )
95
93
  return self._sanitize_storage_options(res)
96
94
 
97
- def _upload(self, key: str, src_path: str, max_chunk_size: int = ONE_GB):
95
+ def _upload(
96
+ self,
97
+ key: str,
98
+ src_path: str,
99
+ max_chunk_size: int = V3IO_DEFAULT_UPLOAD_CHUNK_SIZE,
100
+ ):
98
101
  """helper function for upload method, allows for controlling max_chunk_size in testing"""
99
102
  container, path = split_path(self._join(key))
100
- file_size = os.path.getsize(src_path) # in bytes
101
- if file_size <= ONE_MB:
102
- with open(src_path, "rb") as source_file:
103
- data = source_file.read()
104
- self._do_object_request(
105
- self.object.put,
106
- container=container,
107
- path=path,
108
- body=data,
109
- append=False,
110
- )
111
- return
112
- # chunk must be a multiple of the ALLOCATIONGRANULARITY
113
- # https://docs.python.org/3/library/mmap.html
114
- if residue := max_chunk_size % mmap.ALLOCATIONGRANULARITY:
115
- # round down to the nearest multiple of ALLOCATIONGRANULARITY
116
- max_chunk_size -= residue
117
-
118
103
  with open(src_path, "rb") as file_obj:
119
- file_offset = 0
120
- while file_offset < file_size:
121
- chunk_size = min(file_size - file_offset, max_chunk_size)
122
- with mmap.mmap(
123
- file_obj.fileno(),
124
- length=chunk_size,
125
- access=mmap.ACCESS_READ,
126
- offset=file_offset,
127
- ) as mmap_obj:
128
- append = file_offset != 0
129
- self._do_object_request(
130
- self.object.put,
131
- container=container,
132
- path=path,
133
- body=mmap_obj,
134
- append=append,
135
- )
136
- file_offset += chunk_size
104
+ append = False
105
+ while True:
106
+ data = memoryview(file_obj.read(max_chunk_size))
107
+ if not data:
108
+ break
109
+ self._do_object_request(
110
+ self.object.put,
111
+ container=container,
112
+ path=path,
113
+ body=data,
114
+ append=append,
115
+ )
116
+ append = True
137
117
 
138
118
  def upload(self, key, src_path):
139
119
  return self._upload(key, src_path)
@@ -148,19 +128,16 @@ class V3ioStore(DataStore):
148
128
  num_bytes=size,
149
129
  ).body
150
130
 
151
- def _put(self, key, data, append=False, max_chunk_size: int = ONE_GB):
131
+ def _put(
132
+ self,
133
+ key,
134
+ data,
135
+ append=False,
136
+ max_chunk_size: int = V3IO_DEFAULT_UPLOAD_CHUNK_SIZE,
137
+ ):
152
138
  """helper function for put method, allows for controlling max_chunk_size in testing"""
153
139
  container, path = split_path(self._join(key))
154
140
  buffer_size = len(data) # in bytes
155
- if buffer_size <= ONE_MB:
156
- self._do_object_request(
157
- self.object.put,
158
- container=container,
159
- path=path,
160
- body=data,
161
- append=append,
162
- )
163
- return
164
141
  buffer_offset = 0
165
142
  try:
166
143
  data = memoryview(data)
mlrun/db/auth_utils.py ADDED
@@ -0,0 +1,152 @@
1
+ # Copyright 2024 Iguazio
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from abc import ABC, abstractmethod
16
+ from datetime import datetime, timedelta
17
+
18
+ import requests
19
+
20
+ import mlrun.errors
21
+ from mlrun.utils import logger
22
+
23
+
24
+ class TokenProvider(ABC):
25
+ @abstractmethod
26
+ def get_token(self):
27
+ pass
28
+
29
+ @abstractmethod
30
+ def is_iguazio_session(self):
31
+ pass
32
+
33
+
34
+ class StaticTokenProvider(TokenProvider):
35
+ def __init__(self, token: str):
36
+ self.token = token
37
+
38
+ def get_token(self):
39
+ return self.token
40
+
41
+ def is_iguazio_session(self):
42
+ return mlrun.platforms.iguazio.is_iguazio_session(self.token)
43
+
44
+
45
+ class OAuthClientIDTokenProvider(TokenProvider):
46
+ def __init__(
47
+ self, token_endpoint: str, client_id: str, client_secret: str, timeout=5
48
+ ):
49
+ if not token_endpoint or not client_id or not client_secret:
50
+ raise mlrun.errors.MLRunValueError(
51
+ "Invalid client_id configuration for authentication. Must provide token endpoint, client-id and secret"
52
+ )
53
+ self.token_endpoint = token_endpoint
54
+ self.client_id = client_id
55
+ self.client_secret = client_secret
56
+ self.timeout = timeout
57
+
58
+ # Since we're only issuing POST requests, which are actually a disguised GET, then it's ok to allow retries
59
+ # on them.
60
+ self._session = mlrun.utils.HTTPSessionWithRetry(
61
+ retry_on_post=True,
62
+ verbose=True,
63
+ )
64
+
65
+ self._cleanup()
66
+ self._refresh_token_if_needed()
67
+
68
+ def get_token(self):
69
+ self._refresh_token_if_needed()
70
+ return self.token
71
+
72
+ def is_iguazio_session(self):
73
+ return False
74
+
75
+ def _cleanup(self):
76
+ self.token = self.token_expiry_time = self.token_refresh_time = None
77
+
78
+ def _refresh_token_if_needed(self):
79
+ now = datetime.now()
80
+ if self.token:
81
+ if self.token_refresh_time and now <= self.token_refresh_time:
82
+ return self.token
83
+
84
+ # We only cleanup if token was really expired - even if we fail in refreshing the token, we can still
85
+ # use the existing one given that it's not expired.
86
+ if now >= self.token_expiry_time:
87
+ self._cleanup()
88
+
89
+ self._issue_token_request()
90
+ return self.token
91
+
92
+ def _issue_token_request(self, raise_on_error=False):
93
+ try:
94
+ headers = {"Content-Type": "application/x-www-form-urlencoded"}
95
+ request_body = {
96
+ "grant_type": "client_credentials",
97
+ "client_id": self.client_id,
98
+ "client_secret": self.client_secret,
99
+ }
100
+ response = self._session.request(
101
+ "POST",
102
+ self.token_endpoint,
103
+ timeout=self.timeout,
104
+ headers=headers,
105
+ data=request_body,
106
+ )
107
+ except requests.RequestException as exc:
108
+ error = f"Retrieving token failed: {mlrun.errors.err_to_str(exc)}"
109
+ if raise_on_error:
110
+ raise mlrun.errors.MLRunRuntimeError(error) from exc
111
+ else:
112
+ logger.warning(error)
113
+ return
114
+
115
+ if not response.ok:
116
+ error = "No error available"
117
+ if response.content:
118
+ try:
119
+ data = response.json()
120
+ error = data.get("error")
121
+ except Exception:
122
+ pass
123
+ logger.warning(
124
+ "Retrieving token failed", status=response.status_code, error=error
125
+ )
126
+ if raise_on_error:
127
+ mlrun.errors.raise_for_status(response)
128
+ return
129
+
130
+ self._parse_response(response.json())
131
+
132
+ def _parse_response(self, data: dict):
133
+ # Response is described in https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.3
134
+ # According to spec, there isn't a refresh token - just the access token and its expiry time (in seconds).
135
+ self.token = data.get("access_token")
136
+ expires_in = data.get("expires_in")
137
+ if not self.token or not expires_in:
138
+ token_str = "****" if self.token else "missing"
139
+ logger.warning(
140
+ "Failed to parse token response", token=token_str, expires_in=expires_in
141
+ )
142
+ return
143
+
144
+ now = datetime.now()
145
+ self.token_expiry_time = now + timedelta(seconds=expires_in)
146
+ self.token_refresh_time = now + timedelta(seconds=expires_in / 2)
147
+ logger.info(
148
+ "Successfully retrieved client-id token",
149
+ expires_in=expires_in,
150
+ expiry=str(self.token_expiry_time),
151
+ refresh=str(self.token_refresh_time),
152
+ )
mlrun/db/httpdb.py CHANGED
@@ -33,6 +33,7 @@ import mlrun.common.schemas
33
33
  import mlrun.model_monitoring.model_endpoint
34
34
  import mlrun.platforms
35
35
  import mlrun.projects
36
+ from mlrun.db.auth_utils import OAuthClientIDTokenProvider, StaticTokenProvider
36
37
  from mlrun.errors import MLRunInvalidArgumentError, err_to_str
37
38
 
38
39
  from ..artifacts import Artifact
@@ -133,17 +134,28 @@ class HTTPRunDB(RunDBInterface):
133
134
  endpoint += f":{parsed_url.port}"
134
135
  base_url = f"{parsed_url.scheme}://{endpoint}{parsed_url.path}"
135
136
 
137
+ self.base_url = base_url
136
138
  username = parsed_url.username or config.httpdb.user
137
139
  password = parsed_url.password or config.httpdb.password
140
+ self.token_provider = None
138
141
 
139
- username, password, token = mlrun.platforms.add_or_refresh_credentials(
140
- parsed_url.hostname, username, password, config.httpdb.token
141
- )
142
+ if config.auth_with_client_id.enabled:
143
+ self.token_provider = OAuthClientIDTokenProvider(
144
+ token_endpoint=mlrun.get_secret_or_env("MLRUN_AUTH_TOKEN_ENDPOINT"),
145
+ client_id=mlrun.get_secret_or_env("MLRUN_AUTH_CLIENT_ID"),
146
+ client_secret=mlrun.get_secret_or_env("MLRUN_AUTH_CLIENT_SECRET"),
147
+ timeout=config.auth_with_client_id.request_timeout,
148
+ )
149
+ else:
150
+ username, password, token = mlrun.platforms.add_or_refresh_credentials(
151
+ parsed_url.hostname, username, password, config.httpdb.token
152
+ )
153
+
154
+ if token:
155
+ self.token_provider = StaticTokenProvider(token)
142
156
 
143
- self.base_url = base_url
144
157
  self.user = username
145
158
  self.password = password
146
- self.token = token
147
159
 
148
160
  def __repr__(self):
149
161
  cls = self.__class__.__name__
@@ -213,17 +225,19 @@ class HTTPRunDB(RunDBInterface):
213
225
 
214
226
  if self.user:
215
227
  kw["auth"] = (self.user, self.password)
216
- elif self.token:
217
- # Iguazio auth doesn't support passing token through bearer, so use cookie instead
218
- if mlrun.platforms.iguazio.is_iguazio_session(self.token):
219
- session_cookie = f'j:{{"sid": "{self.token}"}}'
220
- cookies = {
221
- "session": session_cookie,
222
- }
223
- kw["cookies"] = cookies
224
- else:
225
- if "Authorization" not in kw.setdefault("headers", {}):
226
- kw["headers"].update({"Authorization": "Bearer " + self.token})
228
+ elif self.token_provider:
229
+ token = self.token_provider.get_token()
230
+ if token:
231
+ # Iguazio auth doesn't support passing token through bearer, so use cookie instead
232
+ if self.token_provider.is_iguazio_session():
233
+ session_cookie = f'j:{{"sid": "{token}"}}'
234
+ cookies = {
235
+ "session": session_cookie,
236
+ }
237
+ kw["cookies"] = cookies
238
+ else:
239
+ if "Authorization" not in kw.setdefault("headers", {}):
240
+ kw["headers"].update({"Authorization": "Bearer " + token})
227
241
 
228
242
  if mlrun.common.schemas.HeaderNames.client_version not in kw.setdefault(
229
243
  "headers", {}
@@ -930,6 +944,7 @@ class HTTPRunDB(RunDBInterface):
930
944
  kind: str = None,
931
945
  category: Union[str, mlrun.common.schemas.ArtifactCategories] = None,
932
946
  tree: str = None,
947
+ producer_uri: str = None,
933
948
  ) -> ArtifactList:
934
949
  """List artifacts filtered by various parameters.
935
950
 
@@ -956,9 +971,12 @@ class HTTPRunDB(RunDBInterface):
956
971
  :param best_iteration: Returns the artifact which belongs to the best iteration of a given run, in the case of
957
972
  artifacts generated from a hyper-param run. If only a single iteration exists, will return the artifact
958
973
  from that iteration. If using ``best_iter``, the ``iter`` parameter must not be used.
959
- :param kind: Return artifacts of the requested kind.
960
- :param category: Return artifacts of the requested category.
961
- :param tree: Return artifacts of the requested tree.
974
+ :param kind: Return artifacts of the requested kind.
975
+ :param category: Return artifacts of the requested category.
976
+ :param tree: Return artifacts of the requested tree.
977
+ :param producer_uri: Return artifacts produced by the requested producer URI. Producer URI usually
978
+ points to a run and is used to filter artifacts by the run that produced them when the artifact producer id
979
+ is a workflow id (artifact was created as part of a workflow).
962
980
  """
963
981
 
964
982
  project = project or config.default_project
@@ -977,6 +995,7 @@ class HTTPRunDB(RunDBInterface):
977
995
  "category": category,
978
996
  "tree": tree,
979
997
  "format": mlrun.common.schemas.ArtifactsFormat.full.value,
998
+ "producer_uri": producer_uri,
980
999
  }
981
1000
  error = "list artifacts"
982
1001
  endpoint_path = f"projects/{project}/artifacts"
mlrun/lists.py CHANGED
@@ -36,6 +36,7 @@ list_header = [
36
36
  "parameters",
37
37
  "results",
38
38
  "artifacts",
39
+ "artifact_uris",
39
40
  "error",
40
41
  ]
41
42
 
@@ -63,6 +64,7 @@ class RunList(list):
63
64
  get_in(run, "spec.parameters", ""),
64
65
  get_in(run, "status.results", ""),
65
66
  get_in(run, "status.artifacts", []),
67
+ get_in(run, "status.artifact_uris", {}),
66
68
  get_in(run, "status.error", ""),
67
69
  ]
68
70
  if extend_iterations and iterations:
mlrun/model.py CHANGED
@@ -624,6 +624,11 @@ class RunMetadata(ModelObj):
624
624
  def iteration(self, iteration):
625
625
  self._iteration = iteration
626
626
 
627
+ def is_workflow_runner(self):
628
+ if not self.labels:
629
+ return False
630
+ return self.labels.get("job-type", "") == "workflow-runner"
631
+
627
632
 
628
633
  class HyperParamStrategies:
629
634
  grid = "grid"
@@ -1053,6 +1058,7 @@ class RunStatus(ModelObj):
1053
1058
  ui_url=None,
1054
1059
  reason: str = None,
1055
1060
  notifications: Dict[str, Notification] = None,
1061
+ artifact_uris: dict[str, str] = None,
1056
1062
  ):
1057
1063
  self.state = state or "created"
1058
1064
  self.status_text = status_text
@@ -1067,6 +1073,21 @@ class RunStatus(ModelObj):
1067
1073
  self.ui_url = ui_url
1068
1074
  self.reason = reason
1069
1075
  self.notifications = notifications or {}
1076
+ # Artifact key -> URI mapping, since the full artifacts are not stored in the runs DB table
1077
+ self.artifact_uris = artifact_uris or {}
1078
+
1079
+ def is_failed(self) -> Optional[bool]:
1080
+ """
1081
+ This method returns whether a run has failed.
1082
+ Returns none if state has yet to be defined. callee is responsible for handling None.
1083
+ (e.g wait for state to be defined)
1084
+ """
1085
+ if not self.state:
1086
+ return None
1087
+ return self.state.casefold() in [
1088
+ mlrun.run.RunStatuses.failed.casefold(),
1089
+ mlrun.run.RunStatuses.error.casefold(),
1090
+ ]
1070
1091
 
1071
1092
 
1072
1093
  class RunTemplate(ModelObj):
@@ -1366,8 +1387,10 @@ class RunObject(RunTemplate):
1366
1387
  iter=self.metadata.iteration,
1367
1388
  )
1368
1389
  if run:
1369
- self.status = RunStatus.from_dict(run.get("status", {}))
1370
- self.status.from_dict(run.get("status", {}))
1390
+ run_status = run.get("status", {})
1391
+ # Artifacts are not stored in the DB, so we need to preserve them here
1392
+ run_status["artifacts"] = self.status.artifacts
1393
+ self.status = RunStatus.from_dict(run_status)
1371
1394
  return self
1372
1395
 
1373
1396
  def show(self):
@@ -11,7 +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
- #
14
+
15
15
  import abc
16
16
  import collections
17
17
  import dataclasses
@@ -20,13 +20,17 @@ import json
20
20
  import os
21
21
  import re
22
22
  from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union
23
+ from urllib.parse import urlparse
23
24
 
25
+ import fsspec
24
26
  import numpy as np
25
27
  import pandas as pd
28
+ import pyarrow
26
29
  import requests
27
30
  import v3io
28
31
  import v3io.dataplane
29
32
  import v3io_frames
33
+ import v3iofs # noqa: F401, required for V3IO file system with fsspec
30
34
  from v3io_frames.frames_pb2 import IGNORE
31
35
 
32
36
  import mlrun.common.helpers
@@ -720,6 +724,21 @@ class BatchProcessor:
720
724
  )
721
725
  return
722
726
 
727
+ except pyarrow.ArrowInvalid:
728
+ target_path = m_fs.status.targets[0].path
729
+ fs = fsspec.filesystem(urlparse(target_path).scheme)
730
+ paths = fs.glob(target_path + "/**")
731
+ logger.warn(
732
+ "Parquet found, but could not be read. Listing the files "
733
+ "and folders in the model endpoint's parquet folder",
734
+ target_path=target_path,
735
+ paths=paths,
736
+ )
737
+ for path in paths:
738
+ details = fs.listdir(path)
739
+ logger.info("Path details", path=path, details=details)
740
+ raise
741
+
723
742
  # Get feature names from monitoring feature set
724
743
  feature_names = [
725
744
  feature_name["name"] for feature_name in m_fs.spec.features.to_dict()
@@ -350,7 +350,6 @@ class EventStreamProcessor:
350
350
  rate="10/m",
351
351
  time_col=EventFieldType.TIMESTAMP,
352
352
  container=self.tsdb_container,
353
- access_key=self.v3io_access_key,
354
353
  v3io_frames=self.v3io_framesd,
355
354
  infer_columns_from_data=True,
356
355
  index_cols=[
@@ -1079,6 +1078,9 @@ class UpdateEndpoint(mlrun.feature_store.steps.MapClass):
1079
1078
  self.model_endpoint_store_target = model_endpoint_store_target
1080
1079
 
1081
1080
  def do(self, event: dict):
1081
+ # Remove labels from the event
1082
+ event.pop(EventFieldType.LABELS)
1083
+
1082
1084
  update_endpoint_record(
1083
1085
  project=self.project,
1084
1086
  endpoint_id=event.pop(EventFieldType.ENDPOINT_ID),
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
  import abc
15
15
  import builtins
16
+ import http
16
17
  import importlib.util as imputil
17
18
  import os
18
19
  import tempfile
@@ -877,17 +878,33 @@ class _RemoteRunner(_PipelineRunner):
877
878
  get_workflow_id_timeout=get_workflow_id_timeout,
878
879
  )
879
880
 
881
+ def _get_workflow_id_or_bail():
882
+ try:
883
+ return run_db.get_workflow_id(
884
+ project=project.name,
885
+ name=workflow_response.name,
886
+ run_id=workflow_response.run_id,
887
+ engine=workflow_spec.engine,
888
+ )
889
+ except mlrun.errors.MLRunHTTPStatusError as get_wf_exc:
890
+ # fail fast on specific errors
891
+ if get_wf_exc.error_status_code in [
892
+ http.HTTPStatus.PRECONDITION_FAILED
893
+ ]:
894
+ raise mlrun.errors.MLRunFatalFailureError(
895
+ original_exception=get_wf_exc
896
+ )
897
+
898
+ # raise for a retry (on other errors)
899
+ raise
900
+
880
901
  # Getting workflow id from run:
881
902
  response = retry_until_successful(
882
903
  1,
883
904
  get_workflow_id_timeout,
884
905
  logger,
885
906
  False,
886
- run_db.get_workflow_id,
887
- project=project.name,
888
- name=workflow_response.name,
889
- run_id=workflow_response.run_id,
890
- engine=workflow_spec.engine,
907
+ _get_workflow_id_or_bail,
891
908
  )
892
909
  workflow_id = response.workflow_id
893
910
  # After fetching the workflow_id the workflow executed successfully
mlrun/projects/project.py CHANGED
@@ -2650,12 +2650,14 @@ class MlrunProject(ModelObj):
2650
2650
  "Remote repo is not defined, use .create_remote() + push()"
2651
2651
  )
2652
2652
 
2653
- self.sync_functions(always=sync)
2654
- if not self.spec._function_objects:
2655
- raise ValueError(
2656
- "There are no functions in the project."
2657
- " Make sure you've set your functions with project.set_function()."
2658
- )
2653
+ if engine not in ["remote"]:
2654
+ # for remote runs we don't require the functions to be synced as they can be loaded dynamically during run
2655
+ self.sync_functions(always=sync)
2656
+ if not self.spec._function_objects:
2657
+ raise ValueError(
2658
+ "There are no functions in the project."
2659
+ " Make sure you've set your functions with project.set_function()."
2660
+ )
2659
2661
 
2660
2662
  if not name and not workflow_path and not workflow_handler:
2661
2663
  raise ValueError("Workflow name, path, or handler must be specified")
mlrun/render.py CHANGED
@@ -134,7 +134,7 @@ def artifacts_html(
134
134
 
135
135
  if not attribute_value:
136
136
  mlrun.utils.logger.warning(
137
- "Artifact is incomplete, omitting from output (most likely due to a failed artifact logging)",
137
+ f"Artifact required attribute {attribute_name} is missing, omitting from output",
138
138
  artifact_key=key,
139
139
  )
140
140
  continue
@@ -404,12 +404,21 @@ def runs_to_html(
404
404
  df.drop("labels", axis=1, inplace=True)
405
405
  df.drop("inputs", axis=1, inplace=True)
406
406
  df.drop("artifacts", axis=1, inplace=True)
407
+ df.drop("artifact_uris", axis=1, inplace=True)
407
408
  else:
408
409
  df["labels"] = df["labels"].apply(dict_html)
409
410
  df["inputs"] = df["inputs"].apply(inputs_html)
410
- df["artifacts"] = df["artifacts"].apply(
411
- lambda artifacts: artifacts_html(artifacts, "target_path"),
412
- )
411
+ if df["artifacts"][0]:
412
+ df["artifacts"] = df["artifacts"].apply(
413
+ lambda artifacts: artifacts_html(artifacts, "target_path"),
414
+ )
415
+ df.drop("artifact_uris", axis=1, inplace=True)
416
+ elif df["artifact_uris"][0]:
417
+ df["artifact_uris"] = df["artifact_uris"].apply(dict_html)
418
+ df.drop("artifacts", axis=1, inplace=True)
419
+ else:
420
+ df.drop("artifacts", axis=1, inplace=True)
421
+ df.drop("artifact_uris", axis=1, inplace=True)
413
422
 
414
423
  def expand_error(x):
415
424
  if x["state"] == "error":
mlrun/runtimes/pod.py CHANGED
@@ -1012,12 +1012,12 @@ class KubeResource(BaseRuntime):
1012
1012
 
1013
1013
  def _set_env(self, name, value=None, value_from=None):
1014
1014
  new_var = k8s_client.V1EnvVar(name=name, value=value, value_from=value_from)
1015
- i = 0
1016
- for v in self.spec.env:
1017
- if get_item_name(v) == name:
1018
- self.spec.env[i] = new_var
1015
+
1016
+ # ensure we don't have duplicate env vars with the same name
1017
+ for env_index, value_item in enumerate(self.spec.env):
1018
+ if get_item_name(value_item) == name:
1019
+ self.spec.env[env_index] = new_var
1019
1020
  return self
1020
- i += 1
1021
1021
  self.spec.env.append(new_var)
1022
1022
  return self
1023
1023
 
@@ -485,7 +485,11 @@ def _init_endpoint_record(
485
485
  return None
486
486
 
487
487
  # Generating version model value based on the model name and model version
488
- if model.version:
488
+ if model.model_path and model.model_path.startswith("store://"):
489
+ # Enrich the model server with the model artifact metadata
490
+ model.get_model()
491
+ model.version = model.model_spec.tag
492
+ model.labels = model.model_spec.labels
489
493
  versioned_model_name = f"{model.name}:{model.version}"
490
494
  else:
491
495
  versioned_model_name = f"{model.name}:latest"
mlrun/utils/async_http.py CHANGED
@@ -24,7 +24,7 @@ from aiohttp_retry import ExponentialRetry, RequestParams, RetryClient, RetryOpt
24
24
  from aiohttp_retry.client import _RequestContext
25
25
 
26
26
  from mlrun.config import config
27
- from mlrun.errors import err_to_str
27
+ from mlrun.errors import err_to_str, raise_for_status
28
28
 
29
29
  from .helpers import logger as mlrun_logger
30
30
 
@@ -48,12 +48,21 @@ class AsyncClientWithRetry(RetryClient):
48
48
  *args,
49
49
  **kwargs,
50
50
  ):
51
+ # do not retry on PUT / PATCH as they might have side effects (not truly idempotent)
52
+ blacklisted_methods = (
53
+ blacklisted_methods
54
+ if blacklisted_methods is not None
55
+ else [
56
+ "POST",
57
+ "PUT",
58
+ "PATCH",
59
+ ]
60
+ )
51
61
  super().__init__(
52
62
  *args,
53
63
  retry_options=ExponentialRetryOverride(
54
64
  retry_on_exception=retry_on_exception,
55
- # do not retry on PUT / PATCH as they might have side effects (not truly idempotent)
56
- blacklisted_methods=blacklisted_methods or ["POST", "PUT", "PATCH"],
65
+ blacklisted_methods=blacklisted_methods,
57
66
  attempts=max_retries,
58
67
  statuses=retry_on_status_codes,
59
68
  factor=retry_backoff_factor,
@@ -65,6 +74,12 @@ class AsyncClientWithRetry(RetryClient):
65
74
  **kwargs,
66
75
  )
67
76
 
77
+ def methods_blacklist_update_required(self, new_blacklist: str):
78
+ self._retry_options: ExponentialRetryOverride
79
+ return set(self._retry_options.blacklisted_methods).difference(
80
+ set(new_blacklist)
81
+ )
82
+
68
83
  def _make_requests(
69
84
  self,
70
85
  params_list: List[RequestParams],
@@ -175,7 +190,7 @@ class _CustomRequestContext(_RequestContext):
175
190
  last_attempt = current_attempt == self._retry_options.attempts
176
191
  if self._is_status_code_ok(response.status) or last_attempt:
177
192
  if self._raise_for_status:
178
- response.raise_for_status()
193
+ raise_for_status(response)
179
194
 
180
195
  self._response = response
181
196
  return response
@@ -277,6 +292,11 @@ class _CustomRequestContext(_RequestContext):
277
292
  if isinstance(exc.os_error, exc_type):
278
293
  return
279
294
  if exc.__cause__:
280
- return self.verify_exception_type(exc.__cause__)
295
+ # If the cause exception is retriable, return, otherwise, raise the original exception
296
+ try:
297
+ self.verify_exception_type(exc.__cause__)
298
+ except Exception:
299
+ raise exc
300
+ return
281
301
  else:
282
302
  raise exc
mlrun/utils/logger.py CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  import json
16
16
  import logging
17
+ import typing
17
18
  from enum import Enum
18
19
  from sys import stdout
19
20
  from traceback import format_exception
@@ -186,11 +187,15 @@ class FormatterKinds(Enum):
186
187
  JSON = "json"
187
188
 
188
189
 
189
- def create_formatter_instance(formatter_kind: FormatterKinds) -> logging.Formatter:
190
+ def resolve_formatter_by_kind(
191
+ formatter_kind: FormatterKinds,
192
+ ) -> typing.Type[
193
+ typing.Union[HumanReadableFormatter, HumanReadableExtendedFormatter, JSONFormatter]
194
+ ]:
190
195
  return {
191
- FormatterKinds.HUMAN: HumanReadableFormatter(),
192
- FormatterKinds.HUMAN_EXTENDED: HumanReadableExtendedFormatter(),
193
- FormatterKinds.JSON: JSONFormatter(),
196
+ FormatterKinds.HUMAN: HumanReadableFormatter,
197
+ FormatterKinds.HUMAN_EXTENDED: HumanReadableExtendedFormatter,
198
+ FormatterKinds.JSON: JSONFormatter,
194
199
  }[formatter_kind]
195
200
 
196
201
 
@@ -208,11 +213,11 @@ def create_logger(
208
213
  logger_instance = Logger(level, name=name, propagate=False)
209
214
 
210
215
  # resolve formatter
211
- formatter_instance = create_formatter_instance(
216
+ formatter_instance = resolve_formatter_by_kind(
212
217
  FormatterKinds(formatter_kind.lower())
213
218
  )
214
219
 
215
220
  # set handler
216
- logger_instance.set_handler("default", stream or stdout, formatter_instance)
221
+ logger_instance.set_handler("default", stream or stdout, formatter_instance())
217
222
 
218
223
  return logger_instance
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "f92c61e36251c44954e73b3b0809b07df0e9833a",
3
- "version": "1.6.3-rc3"
2
+ "git_commit": "c86187656ea8299187cdca54869c77d341eb58d4",
3
+ "version": "1.6.4-rc2"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mlrun
3
- Version: 1.6.3rc3
3
+ Version: 1.6.4rc2
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -26,7 +26,7 @@ Requires-Dist: GitPython >=3.1.41,~=3.1
26
26
  Requires-Dist: aiohttp ~=3.9
27
27
  Requires-Dist: aiohttp-retry ~=2.8
28
28
  Requires-Dist: click ~=8.1
29
- Requires-Dist: kfp ~=1.8
29
+ Requires-Dist: kfp >=1.8.14,~=1.8
30
30
  Requires-Dist: nest-asyncio ~=1.0
31
31
  Requires-Dist: ipython ~=8.10
32
32
  Requires-Dist: nuclio-jupyter ~=0.9.15
@@ -89,6 +89,7 @@ Requires-Dist: sqlalchemy ~=1.4 ; extra == 'api'
89
89
  Requires-Dist: pymysql ~=1.0 ; extra == 'api'
90
90
  Requires-Dist: alembic ~=1.9 ; extra == 'api'
91
91
  Requires-Dist: timelength ~=1.1 ; extra == 'api'
92
+ Requires-Dist: memray ~=1.12 ; extra == 'api'
92
93
  Provides-Extra: azure-blob-storage
93
94
  Requires-Dist: msrest ~=0.6.21 ; extra == 'azure-blob-storage'
94
95
  Requires-Dist: azure-core ~=1.24 ; extra == 'azure-blob-storage'
@@ -143,6 +144,7 @@ Requires-Dist: graphviz ~=0.20.0 ; extra == 'complete-api'
143
144
  Requires-Dist: humanfriendly ~=10.0 ; extra == 'complete-api'
144
145
  Requires-Dist: igz-mgmt ==0.1.0 ; extra == 'complete-api'
145
146
  Requires-Dist: kafka-python ~=2.0 ; extra == 'complete-api'
147
+ Requires-Dist: memray ~=1.12 ; extra == 'complete-api'
146
148
  Requires-Dist: mlflow ~=2.8 ; extra == 'complete-api'
147
149
  Requires-Dist: msrest ~=0.6.21 ; extra == 'complete-api'
148
150
  Requires-Dist: objgraph ~=3.6 ; extra == 'complete-api'
@@ -1,14 +1,14 @@
1
1
  mlrun/__init__.py,sha256=o9dHUfVFADfsi6GnOPLr2OkfkHdPvOnA7rkoECen0-I,7248
2
2
  mlrun/__main__.py,sha256=zd-o0SkFH69HhIWKhqXnNURsrtpIcOJYYq50JfAxW7k,49234
3
- mlrun/config.py,sha256=ZBPscgl5DgSgiG8gsHK6Z5fyWHh9r17hXVnYAZAAiWY,63454
3
+ mlrun/config.py,sha256=4scerZD_BdeDIOXJw9xrXCmpSBHxEvuc7R9QZpAb5EA,63789
4
4
  mlrun/errors.py,sha256=YdUtkN3qJ6yrseNygmKxmSWOfQ_RdKBhRxwwyMlTQCM,7106
5
5
  mlrun/execution.py,sha256=tgp6PcujZvGhDDVzPNs32YH_JNzaxfSd25yeuLwmjzg,40880
6
6
  mlrun/features.py,sha256=UQQ2uh5Xh9XsMGiYBqh3bKgDhOHANjv1gQgWyId9qQE,15624
7
7
  mlrun/k8s_utils.py,sha256=-6egUEZNPhzOxJ2gFytubvQvCYU9nPPg5Yn0zsTK-NQ,7065
8
8
  mlrun/kfpops.py,sha256=VgvS_4DappCPHzV7057SbraBTbF2mn7zZ7iPAaks3KU,30493
9
- mlrun/lists.py,sha256=JMc4Ch4wQxD_B9zbrE3JZwXD8cCYWLqHb1FQXWoaGzM,8310
10
- mlrun/model.py,sha256=Ggz9D8YCHCFluJQe1aPiddK1Mr34LYREirqJLa2i7IU,63956
11
- mlrun/render.py,sha256=_Jrtqw54AkvUZDWK5ORGUQWnGewREh_lQnUQWuCkTV4,13016
9
+ mlrun/lists.py,sha256=sEEfl_mw_oVUD1dfkvQZIkJ8q7LJKJPDrb5B_Dg85nY,8388
10
+ mlrun/model.py,sha256=EbSxpwtNFkqodTwM_StcmDG5MFSG50ZuDMhqzIyzLmM,64896
11
+ mlrun/render.py,sha256=pfAky9fTHRbINs93_Km_hEdVxmra9RA8BwqMepPbiuE,13451
12
12
  mlrun/run.py,sha256=gyxYJqVCBsZxp0_HWAG5_lwi2_KPqcxy6un5ZLw_-2Q,42456
13
13
  mlrun/secrets.py,sha256=m7jM8fdjGLR-j9Vx-08eNmtOmlxFx9mTUBqBWtMSVQo,7782
14
14
  mlrun/api/schemas/__init__.py,sha256=ggWbnqhp7By5HNYYfRsZ4D4EdVvjLuz4qfNfR3Kq6M4,14219
@@ -72,7 +72,6 @@ mlrun/datastore/datastore_profile.py,sha256=vBpkAcnGiYUO09ihg_jPgPdpo2GVBrOOSHYW
72
72
  mlrun/datastore/dbfs_store.py,sha256=5IkxnFQXkW0fdx-ca5jjQnUdTsTfNdJzMvV31ZpDNrM,6634
73
73
  mlrun/datastore/filestore.py,sha256=cI_YvQqY5J3kEvdyPelfWofxKfBitoNHJvABBkpCGRc,3788
74
74
  mlrun/datastore/google_cloud_storage.py,sha256=zQlrZnYOFfwQNBw5J2ufoyCDMlbZKA9c9no7NvnylZ4,6038
75
- mlrun/datastore/helpers.py,sha256=-bKveE9rteLd0hJd6OSMuMbfz09W_OXyu1G5O2ihZjs,622
76
75
  mlrun/datastore/inmem.py,sha256=6PAltUk7uyYlDgnsaJPOkg_P98iku1ys2e2wpAmPRkc,2779
77
76
  mlrun/datastore/redis.py,sha256=DDA1FsixfnzNwjVUU9MgVCKFo3X3tYvPDcREKyy9zS4,5517
78
77
  mlrun/datastore/s3.py,sha256=BCyVDznEsmU1M1HtRROdLo4HkLOy4fjEmgpNrTpsoW0,8030
@@ -82,13 +81,14 @@ mlrun/datastore/spark_utils.py,sha256=54rF64aC19ojUFCcwzsoBLQ-5Nmzs_KTQl9iEkK2hY
82
81
  mlrun/datastore/store_resources.py,sha256=dfMdFy2urilECtlwLJr5CSG12MA645b-NPYDnbr5s1A,6839
83
82
  mlrun/datastore/targets.py,sha256=EaeNzwHQHkMo7WRezgMeWWjTL1NmYwMx8F0RG1swb48,70159
84
83
  mlrun/datastore/utils.py,sha256=x4pm0gvpcNWSjxo99MOmwcd9I5HCwuzCh6IA4uiXlZs,7077
85
- mlrun/datastore/v3io.py,sha256=OyldGthdycuk7thQYHuCY-2XrGIef_14c2ReqgHh_7I,9188
84
+ mlrun/datastore/v3io.py,sha256=3UI22DQ1A4yQEpbMWAbopIzjqlL2k5bhmhg0Cjs3tEk,8039
86
85
  mlrun/datastore/wasbfs/__init__.py,sha256=s5Ul-0kAhYqFjKDR2X0O2vDGDbLQQduElb32Ev56Te4,1343
87
86
  mlrun/datastore/wasbfs/fs.py,sha256=MnSj7Q4OKA2L55ihCmUnj2t3GA3B77oLMdAw-yxvN9w,6151
88
87
  mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
88
+ mlrun/db/auth_utils.py,sha256=hpg8D2r82oN0BWabuWN04BTNZ7jYMAF242YSUpK7LFM,5211
89
89
  mlrun/db/base.py,sha256=Rg2TrcwvzN28vmoyhq8sSxNjiBS1EA6BAHr24fhcmNU,18221
90
90
  mlrun/db/factory.py,sha256=wTEKHEmdDkylM6IkTYvmEYVF8gn2HdjLoLoWICCyatI,2403
91
- mlrun/db/httpdb.py,sha256=gE01kWA7IwZqO9QTVCJ-YeGAnuwlEvxt-9q14pUfNfI,156147
91
+ mlrun/db/httpdb.py,sha256=FHrAwU7c4AQPCoXDIdkEkFfr8ViUS7XLJYIGrXrv_rs,157292
92
92
  mlrun/db/nopdb.py,sha256=rpZy5cpW-8--4OvMzlVoKNYjbhWJ3cn_z-JFwfuPqnI,14520
93
93
  mlrun/feature_store/__init__.py,sha256=n1F5m1svFW2chbE2dJdWzZJJiYS4E-y8PQsG9Q-F0lU,1584
94
94
  mlrun/feature_store/api.py,sha256=ehEwKlmE07pq1FUwh-ehA8Jm9LTkQofl5MQpEiMwVqM,49520
@@ -198,7 +198,7 @@ mlrun/launcher/remote.py,sha256=lcVV9nH_SMDsdb2XNg01EVnzZSxAMqxFGZJWxaezXeU,7487
198
198
  mlrun/model_monitoring/__init__.py,sha256=XaYyvWsIXpjJQ2gCPj8tFvfSbRSEEqgDtNz4tCE5H4g,915
199
199
  mlrun/model_monitoring/api.py,sha256=uKT733p3vUsIgX-vdvhbroeN15bmdkZT5S3gsfwbNhk,36829
200
200
  mlrun/model_monitoring/application.py,sha256=ilslJNkq3CCivPqvsDOPmu0UClWXwH9IWr58gdxM9iU,12292
201
- mlrun/model_monitoring/batch.py,sha256=l0FTSTt9frLgqeSS9jY8IU_0OwlvSevuZBWBgnBGH9A,43566
201
+ mlrun/model_monitoring/batch.py,sha256=UDtcafDFOqWtARY6lbSdXgMFIO-VYWdKbGUwY_fqfRo,44379
202
202
  mlrun/model_monitoring/controller.py,sha256=Zh7XnGevQyJCU8uMT8MC6kD7cP55vUJaIjqbBvSyuvA,27608
203
203
  mlrun/model_monitoring/controller_handler.py,sha256=kG3sTjhKdsd9QcHkUlYcvw08yPsVQs9FyFdcKP9iaCo,977
204
204
  mlrun/model_monitoring/evidently_application.py,sha256=o9PsDsjyRfcbuC1X1gb2ww5nzWCsR_KheabtpxKZ5yY,4824
@@ -206,7 +206,7 @@ mlrun/model_monitoring/features_drift_table.py,sha256=OEDb_YZm3cyzszzC4SDqi7ufwO
206
206
  mlrun/model_monitoring/helpers.py,sha256=l8RCxOGBoScZSL4M-x4fIfpsfH7wjSQpqA_t-HVk0BI,7087
207
207
  mlrun/model_monitoring/model_endpoint.py,sha256=BBtxdY5ciormI_al4zshmIp0GN7hGhOCn-hLgpCXek0,3938
208
208
  mlrun/model_monitoring/prometheus.py,sha256=Z0UWmhQ-dpGGH31gCiGdfmhfj-RFRf1Tu1bYVe-k4jk,7605
209
- mlrun/model_monitoring/stream_processing.py,sha256=BxdyIn65sv_IBDTAwoNOiNq8a6uks_pJUaY5z9-F4-Q,49203
209
+ mlrun/model_monitoring/stream_processing.py,sha256=n1UpOsxOW8bUQnEAHgRm2wOOihx8VWrFYiE1FWz_zgs,49231
210
210
  mlrun/model_monitoring/tracking_policy.py,sha256=Q6_p4y1ZcRHqs24c_1_4m9E1gYnaOm6pLCNGT22dWKM,5221
211
211
  mlrun/model_monitoring/writer.py,sha256=IWPzPenoAkfIxlvn0IdcdB19Nxqmg4mjbo3-RnYWw9A,8669
212
212
  mlrun/model_monitoring/stores/__init__.py,sha256=adU_G07jkD3JUT8__d0jAxs9nNomL7igKmd6uVM9L50,4525
@@ -239,8 +239,8 @@ mlrun/platforms/iguazio.py,sha256=eOO8CbeSD0ooUKp-hbXbRfzWo5OTP7QaBo6zh0BXTKc,19
239
239
  mlrun/platforms/other.py,sha256=z4pWqxXkVVuMLk-MbNb0Y_ZR5pmIsUm0R8vHnqpEnew,11852
240
240
  mlrun/projects/__init__.py,sha256=Lv5rfxyXJrw6WGOWJKhBz66M6t3_zsNMCfUD6waPwx4,1153
241
241
  mlrun/projects/operations.py,sha256=CJRGKEFhqKXlg0VOKhcfjOUVAmWHA9WwAFNiXtUqBhg,18550
242
- mlrun/projects/pipelines.py,sha256=D4Ny3znuThM2IO6drxJBqlHY_Ipaiiqf2xwETXzp08E,40481
243
- mlrun/projects/project.py,sha256=ShoPjF2l3d_jp6nAWEfgxOwFUZoolMlr5RNSXGrOe1U,153100
242
+ mlrun/projects/pipelines.py,sha256=FcKNsFtRUP1sOuSEp5Hk0_Qv4ZIKT9gWpatg6bSUCsI,41165
243
+ mlrun/projects/project.py,sha256=U98H5DF0q17qZcQB4VqqPoEETFgh_VvV51DTHXQhsbA,153280
244
244
  mlrun/runtimes/__init__.py,sha256=f5cdEg4raKNXQawJE-AuWzK6AqIsLfDODREeMnI2Ies,7062
245
245
  mlrun/runtimes/base.py,sha256=GTVqCR3sBqbyAlEBnDClThOf0EZUoAMzlEIFqjfoyLQ,36604
246
246
  mlrun/runtimes/constants.py,sha256=tB7nIlHob3yF0K9Uf9BUZ8yxjZNSzlzrd3K32K_vV7w,9550
@@ -252,7 +252,7 @@ mlrun/runtimes/generators.py,sha256=v28HdNgxdHvj888G1dTnUeQZz-D9iTO0hoGeZbCdiuQ,
252
252
  mlrun/runtimes/kubejob.py,sha256=UfSm7hiPLAtM0TfIE5nbBdSvrbsKWCZfvKP-SZhGyAk,12500
253
253
  mlrun/runtimes/local.py,sha256=depdJkbyas7V7SMXB1T6Y_jPXxTLEB1TL5HYzDxlcXI,21791
254
254
  mlrun/runtimes/nuclio.py,sha256=hwk4dUaZefI-Qbb4s289vQpt1h0nAucxf6eINzVI-d8,2908
255
- mlrun/runtimes/pod.py,sha256=CBhKyNC20zCaRShS5UkgMR_61w_DpzEtEQ03T8J7u0k,56780
255
+ mlrun/runtimes/pod.py,sha256=loo1ysAbGslrHRhcRaFrw-ATNhuOBayEb0MCPi2EduY,56865
256
256
  mlrun/runtimes/remotesparkjob.py,sha256=W7WqlPbyqE6FjOZ2EFeOzlL1jLGWAWe61jOH0Umy3F4,7334
257
257
  mlrun/runtimes/serving.py,sha256=bV4Io-8K30IZs69pdZTSICR3HkUAAc1kSKuBJOx_jc0,30331
258
258
  mlrun/runtimes/utils.py,sha256=mNVu3ejmfEV3d7-fCAiSaF5K-Jyz2ladc5HzqhsY0Cs,16025
@@ -275,21 +275,21 @@ mlrun/serving/serving_wrapper.py,sha256=R670-S6PX_d5ER6jiHtRvacuPyFzQH0mEf2K0sBI
275
275
  mlrun/serving/states.py,sha256=LORqEyNR6Rxq-rH0VfVvJ_aff3ws_KoT83UqXNccjyY,54821
276
276
  mlrun/serving/utils.py,sha256=PbXvmkqUAAE0jAfnsUwTOHEQsnhMpmuREv_yB21hvv4,3784
277
277
  mlrun/serving/v1_serving.py,sha256=5BVvsvjG4zsq3LMnYp0ZE8qFs-qcfQSD3SOSziEYQqQ,11813
278
- mlrun/serving/v2_serving.py,sha256=fAMA52lBvpLFpUa8LKHjRAwBZp_sR0wUmmtrN1ChJC4,21823
278
+ mlrun/serving/v2_serving.py,sha256=kZO5b-3MXD-ejwH47Kq0klvWn0INqC4vUsHgZyUBqbU,22055
279
279
  mlrun/track/__init__.py,sha256=LWRUHJt8JyFW17FyNPOVyWd-NXTf1iptzsK9KFj5fuY,765
280
280
  mlrun/track/tracker.py,sha256=y-UdhC2nzM6r-yHCwvrfiHRr93xsr4JRsZTxDrTTRJo,3541
281
281
  mlrun/track/tracker_manager.py,sha256=ZZzXtgQ-t4ah64XeAHNCbZ2VMOK_0E0RHv0pIowynjA,5732
282
282
  mlrun/track/trackers/__init__.py,sha256=9xft8YjJnblwqt8f05htmOt_eDzVBVQN07RfY_SYLCs,569
283
283
  mlrun/track/trackers/mlflow_tracker.py,sha256=zqqnECpxk_CHDKzEIdjwL9QUjXfueOw7xlZU7buguKY,23282
284
284
  mlrun/utils/__init__.py,sha256=g2pbT3loDw0GWELOC_rBq1NojSMCFnWrD-TYcDgAZiI,826
285
- mlrun/utils/async_http.py,sha256=N-zkACdr2CZNwYyMaocSR6ZH90F_WV_ZRBVe9ssi-Ns,11141
285
+ mlrun/utils/async_http.py,sha256=J3z4dzU1zk96k1sLDiGUIciBu3pdgivqh-GExFv-Fn8,11773
286
286
  mlrun/utils/azure_vault.py,sha256=IbPAZh-7mp0j4PcCy1L079LuEA6ENrkWhKZvkD4lcTY,3455
287
287
  mlrun/utils/clones.py,sha256=QG2ka65-ysfrOaoziudEjJqGgAxJvFKZOXkiD9WZGN4,7386
288
288
  mlrun/utils/condition_evaluator.py,sha256=KFZC-apM7RU5TIlRszAzMFc0NqPj3W1rgP0Zv17Ud-A,1918
289
289
  mlrun/utils/db.py,sha256=fp9p2_z7XW3DhsceJEObWKh-e5zKjPiCM55kSGNkZD8,1658
290
290
  mlrun/utils/helpers.py,sha256=MRfvRQlxh9IITpYX68Sc8Lnej-SB5sWzIAy_7NhB44o,53692
291
291
  mlrun/utils/http.py,sha256=BLkPfCmXwFrpPrPXzipmDr9IhY3q5css7hovncXYs9g,8735
292
- mlrun/utils/logger.py,sha256=3SS-9ON0ScnUJp1S6P_jmaTRXuwF6MhBF5a5Ij8s3IU,7158
292
+ mlrun/utils/logger.py,sha256=KZFzojroEshCu1kvtCsavJpdIY8vNA-QZxiBjehP9f4,7260
293
293
  mlrun/utils/regex.py,sha256=Nd7xnDHU9PEOsse6rFwLNVgU4AaYCyuwMmQ9qgx2-Vw,4581
294
294
  mlrun/utils/singleton.py,sha256=UUTQiBTXyzmjeYzsvTUsSxqyLJHOtesqif9GNfZO9rc,883
295
295
  mlrun/utils/v3io_clients.py,sha256=HL7Hma-pxaQBXMKcEnWqGLCpFgykwnszlabzeOHC9-E,1319
@@ -304,11 +304,11 @@ mlrun/utils/notifications/notification/ipython.py,sha256=qrBmtECiRG6sZpCIVMg7RZc
304
304
  mlrun/utils/notifications/notification/slack.py,sha256=5JysqIpUYUZKXPSeeZtbl7qb2L9dj7p2NvnEBcEsZkA,3898
305
305
  mlrun/utils/notifications/notification/webhook.py,sha256=QHezCuN5uXkLcroAGxGrhGHaxAdUvkDLIsp27_Yrfd4,2390
306
306
  mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
307
- mlrun/utils/version/version.json,sha256=ovTkFroRp8yK9muMbmHjyumPOPF89_2kauo4wAOR8YM,88
307
+ mlrun/utils/version/version.json,sha256=Q1XKNRUFqvGup80Doax-QDFnhlW1SBqds8YVSMUdpWQ,88
308
308
  mlrun/utils/version/version.py,sha256=HMwseV8xjTQ__6T6yUWojx_z6yUj7Io7O4NcCCH_sz8,1970
309
- mlrun-1.6.3rc3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
310
- mlrun-1.6.3rc3.dist-info/METADATA,sha256=Px_p_j9UC_IZpusnSEBkMkI9OpbucofXkrowYv_8EPs,18293
311
- mlrun-1.6.3rc3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
312
- mlrun-1.6.3rc3.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
313
- mlrun-1.6.3rc3.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
314
- mlrun-1.6.3rc3.dist-info/RECORD,,
309
+ mlrun-1.6.4rc2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
310
+ mlrun-1.6.4rc2.dist-info/METADATA,sha256=49UkCKVL5gmj1VoHLfNuutZvtOyeO0OwVNfSYYgYJDc,18403
311
+ mlrun-1.6.4rc2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
312
+ mlrun-1.6.4rc2.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
313
+ mlrun-1.6.4rc2.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
314
+ mlrun-1.6.4rc2.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- # Copyright 2023 Iguazio
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- #
15
-
16
-
17
- ONE_GB = 1024 * 1024 * 1024
18
- ONE_MB = 1024 * 1024