mlrun 1.8.0rc62__py3-none-any.whl → 1.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mlrun might be problematic. Click here for more details.

mlrun/__main__.py CHANGED
@@ -13,6 +13,8 @@
13
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
+ import functools
17
+ import importlib.metadata
16
18
  import json
17
19
  import pathlib
18
20
  import socket
@@ -25,12 +27,14 @@ from pprint import pprint
25
27
  import click
26
28
  import dotenv
27
29
  import pandas as pd
30
+ import semver
28
31
  import yaml
29
32
  from tabulate import tabulate
30
33
 
31
34
  import mlrun
32
35
  import mlrun.common.constants as mlrun_constants
33
36
  import mlrun.common.schemas
37
+ import mlrun.platforms
34
38
  import mlrun.utils.helpers
35
39
  from mlrun.common.helpers import parse_versioned_object_uri
36
40
  from mlrun.runtimes.mounts import auto_mount as auto_mount_modifier
@@ -63,16 +67,22 @@ from .utils.version import Version
63
67
  pd.set_option("mode.chained_assignment", None)
64
68
 
65
69
 
66
- def validate_base_argument(ctx, param, value):
70
+ def validate_base_argument(ctx: click.Context, param: click.Parameter, value: str):
71
+ # click 8.2 expects the context to be passed to make_metavar
72
+ if semver.VersionInfo.parse(
73
+ importlib.metadata.version("click")
74
+ ) < semver.VersionInfo.parse("8.2.0"):
75
+ metavar_func = functools.partial(param.make_metavar)
76
+ else:
77
+ metavar_func = functools.partial(param.make_metavar, ctx)
67
78
  if value and value.startswith("-"):
68
79
  raise click.BadParameter(
69
80
  f"{param.human_readable_name} ({value}) cannot start with '-', ensure the command options are typed "
70
81
  f"correctly. Preferably use '--' to separate options and arguments "
71
- f"e.g. 'mlrun run --option1 --option2 -- {param.make_metavar()} [--arg1|arg1] [--arg2|arg2]'",
82
+ f"e.g. 'mlrun run --option1 --option2 -- {metavar_func()} [--arg1|arg1] [--arg2|arg2]'",
72
83
  ctx=ctx,
73
84
  param=param,
74
85
  )
75
-
76
86
  return value
77
87
 
78
88
 
mlrun/common/constants.py CHANGED
@@ -90,6 +90,13 @@ class MLRunInternalLabels:
90
90
  if not key.startswith("__") and isinstance(value, str)
91
91
  ]
92
92
 
93
+ @staticmethod
94
+ def default_run_labels_to_enrich():
95
+ return [
96
+ MLRunInternalLabels.owner,
97
+ MLRunInternalLabels.v3io_user,
98
+ ]
99
+
93
100
 
94
101
  class DeployStatusTextKind(mlrun.common.types.StrEnum):
95
102
  logs = "logs"
mlrun/config.py CHANGED
@@ -64,7 +64,7 @@ default_config = {
64
64
  # url to nuclio dashboard api (can be with user & token, e.g. https://username:password@dashboard-url.com)
65
65
  "nuclio_dashboard_url": "",
66
66
  "nuclio_version": "",
67
- "default_nuclio_runtime": "python:3.9",
67
+ "default_nuclio_runtime": "python:3.11",
68
68
  "nest_asyncio_enabled": "", # enable import of nest_asyncio for corner cases with old jupyter, set "1"
69
69
  "ui_url": "", # remote/external mlrun UI url (for hyperlinks) (This is deprecated in favor of the ui block)
70
70
  "remote_host": "",
@@ -79,7 +79,7 @@ default_config = {
79
79
  # comma separated list of images that are in the specified images_registry, and therefore will be enriched with this
80
80
  # registry when used. default to mlrun/* which means any image which is of the mlrun repository (mlrun/mlrun,
81
81
  # mlrun/ml-base, etc...)
82
- "images_to_enrich_registry": "^mlrun/*,python:3.9",
82
+ "images_to_enrich_registry": "^mlrun/*,^python:3.(9|11)$",
83
83
  "kfp_url": "",
84
84
  "kfp_ttl": "14400", # KFP ttl in sec, after that completed PODs will be deleted
85
85
  "kfp_image": "mlrun/mlrun-kfp", # image to use for KFP runner
@@ -286,7 +286,7 @@ default_config = {
286
286
  "remote": "mlrun/mlrun",
287
287
  "dask": "mlrun/ml-base",
288
288
  "mpijob": "mlrun/mlrun",
289
- "application": "python:3.9",
289
+ "application": "python",
290
290
  },
291
291
  # see enrich_function_preemption_spec for more info,
292
292
  # and mlrun.common.schemas.function.PreemptionModes for available options
@@ -255,7 +255,7 @@ class DatastoreProfileS3(DatastoreProfile):
255
255
  def check_bucket(cls, v):
256
256
  if not v:
257
257
  warnings.warn(
258
- "The 'bucket' attribute will be mandatory starting from version 1.9",
258
+ "The 'bucket' attribute will be mandatory starting from version 1.10",
259
259
  FutureWarning,
260
260
  stacklevel=2,
261
261
  )
@@ -360,7 +360,7 @@ class DatastoreProfileGCS(DatastoreProfile):
360
360
  def check_bucket(cls, v):
361
361
  if not v:
362
362
  warnings.warn(
363
- "The 'bucket' attribute will be mandatory starting from version 1.9",
363
+ "The 'bucket' attribute will be mandatory starting from version 1.10",
364
364
  FutureWarning,
365
365
  stacklevel=2,
366
366
  )
@@ -417,7 +417,7 @@ class DatastoreProfileAzureBlob(DatastoreProfile):
417
417
  def check_container(cls, v):
418
418
  if not v:
419
419
  warnings.warn(
420
- "The 'container' attribute will be mandatory starting from version 1.9",
420
+ "The 'container' attribute will be mandatory starting from version 1.10",
421
421
  FutureWarning,
422
422
  stacklevel=2,
423
423
  )
mlrun/db/httpdb.py CHANGED
@@ -21,7 +21,7 @@ import typing
21
21
  import warnings
22
22
  from copy import deepcopy
23
23
  from datetime import datetime, timedelta
24
- from os import path, remove
24
+ from os import environ, path, remove
25
25
  from typing import Literal, Optional, Union
26
26
  from urllib.parse import urlparse
27
27
 
@@ -129,7 +129,9 @@ class HTTPRunDB(RunDBInterface):
129
129
  self._wait_for_background_task_terminal_state_retry_interval = 3
130
130
  self._wait_for_project_deletion_interval = 3
131
131
  self.client_version = version.Version().get()["version"]
132
- self.python_version = str(version.Version().get_python_version())
132
+ self.python_version = environ.get("MLRUN_PYTHON_VERSION") or str(
133
+ version.Version().get_python_version()
134
+ )
133
135
 
134
136
  self._enrich_and_validate(url)
135
137
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  from typing import Any, Optional, Union
16
16
 
17
- from tensorflow import keras
17
+ import tensorflow as tf
18
18
 
19
19
  import mlrun
20
20
  import mlrun.common.constants as mlrun_constants
@@ -27,11 +27,11 @@ from .utils import TFKerasTypes, TFKerasUtils
27
27
 
28
28
 
29
29
  def apply_mlrun(
30
- model: keras.Model = None,
30
+ model: tf.keras.Model = None,
31
31
  model_name: Optional[str] = None,
32
32
  tag: str = "",
33
33
  model_path: Optional[str] = None,
34
- model_format: str = TFKerasModelHandler.ModelFormats.SAVED_MODEL,
34
+ model_format: Optional[str] = None,
35
35
  save_traces: bool = False,
36
36
  modules_map: Optional[Union[dict[str, Union[None, str, list[str]]], str]] = None,
37
37
  custom_objects_map: Optional[Union[dict[str, Union[str, list[str]]], str]] = None,
@@ -54,7 +54,7 @@ def apply_mlrun(
54
54
  :param model_path: The model's store object path. Mandatory for evaluation (to know which model to
55
55
  update). If model is not provided, it will be loaded from this path.
56
56
  :param model_format: The format to use for saving and loading the model. Should be passed as a
57
- member of the class 'ModelFormats'. Default: 'ModelFormats.SAVED_MODEL'.
57
+ member of the class 'ModelFormats'.
58
58
  :param save_traces: Whether or not to use functions saving (only available for the 'SavedModel'
59
59
  format) for loading the model later without the custom objects dictionary. Only
60
60
  from tensorflow version >= 2.4.0. Using this setting will increase the model
@@ -16,14 +16,14 @@ from typing import Callable, Optional, Union
16
16
 
17
17
  import numpy as np
18
18
  import tensorflow as tf
19
- from tensorflow import Tensor, Variable
19
+ from tensorflow import keras
20
20
  from tensorflow.python.keras.callbacks import Callback
21
21
 
22
22
  import mlrun
23
23
 
24
24
  from ..._common import LoggingMode
25
25
  from ..._dl_common.loggers import Logger
26
- from ..utils import TFKerasTypes
26
+ from ..utils import TFKerasTypes, is_keras_3
27
27
 
28
28
 
29
29
  class LoggingCallback(Callback):
@@ -70,7 +70,7 @@ class LoggingCallback(Callback):
70
70
  {
71
71
  "epochs": 7
72
72
  }
73
- :param auto_log: Whether or not to enable auto logging, trying to track common static and dynamic
73
+ :param auto_log: Whether to enable auto logging, trying to track common static and dynamic
74
74
  hyperparameters.
75
75
  """
76
76
  super().__init__()
@@ -385,18 +385,24 @@ class LoggingCallback(Callback):
385
385
  self._logger.log_context_parameters()
386
386
 
387
387
  # Add learning rate:
388
- learning_rate_key = "lr"
389
- learning_rate_key_chain = ["optimizer", "lr"]
390
- if learning_rate_key not in self._dynamic_hyperparameters_keys and hasattr(
391
- self.model, "optimizer"
392
- ):
393
- try:
394
- self._get_hyperparameter(key_chain=learning_rate_key_chain)
388
+ learning_rate_keys = [
389
+ "learning_rate",
390
+ "lr",
391
+ ] # "lr" is for backward compatibility in older keras versions.
392
+ if all(
393
+ learning_rate_key not in self._dynamic_hyperparameters_keys
394
+ for learning_rate_key in learning_rate_keys
395
+ ) and hasattr(self.model, "optimizer"):
396
+ for learning_rate_key in learning_rate_keys:
397
+ learning_rate_key_chain = ["optimizer", learning_rate_key]
398
+ try:
399
+ self._get_hyperparameter(key_chain=learning_rate_key_chain)
400
+ except (KeyError, IndexError, AttributeError, ValueError):
401
+ continue
395
402
  self._dynamic_hyperparameters_keys[learning_rate_key] = (
396
403
  learning_rate_key_chain
397
404
  )
398
- except (KeyError, IndexError, ValueError):
399
- pass
405
+ break
400
406
 
401
407
  def _get_hyperparameter(
402
408
  self,
@@ -427,7 +433,7 @@ class LoggingCallback(Callback):
427
433
  value = value[key]
428
434
  else:
429
435
  value = getattr(value, key)
430
- except KeyError or IndexError as KeyChainError:
436
+ except KeyError or IndexError or AttributeError as KeyChainError:
431
437
  raise KeyChainError(
432
438
  f"Error during getting a hyperparameter value with the key chain {key_chain}. "
433
439
  f"The {value.__class__} in it does not have the following key/index from the key provided: "
@@ -435,7 +441,9 @@ class LoggingCallback(Callback):
435
441
  )
436
442
 
437
443
  # Parse the value:
438
- if isinstance(value, Tensor) or isinstance(value, Variable):
444
+ if isinstance(value, (tf.Tensor, tf.Variable)) or (
445
+ is_keras_3() and isinstance(value, (keras.KerasTensor, keras.Variable))
446
+ ):
439
447
  if int(tf.size(value)) == 1:
440
448
  value = float(value)
441
449
  else:
@@ -451,12 +459,7 @@ class LoggingCallback(Callback):
451
459
  f"The parameter with the following key chain: {key_chain} is a numpy.ndarray with {value.size} "
452
460
  f"elements. numpy arrays are trackable only if they have 1 element."
453
461
  )
454
- elif not (
455
- isinstance(value, float)
456
- or isinstance(value, int)
457
- or isinstance(value, str)
458
- or isinstance(value, bool)
459
- ):
462
+ elif not (isinstance(value, (float, int, str, bool))):
460
463
  raise mlrun.errors.MLRunInvalidArgumentError(
461
464
  f"The parameter with the following key chain: {key_chain} is of type '{type(value)}'. The only "
462
465
  f"trackable types are: float, int, str and bool."
@@ -29,7 +29,7 @@ from mlrun.features import Feature
29
29
  from .._common import without_mlrun_interface
30
30
  from .._dl_common import DLModelHandler
31
31
  from .mlrun_interface import TFKerasMLRunInterface
32
- from .utils import TFKerasUtils
32
+ from .utils import TFKerasUtils, is_keras_3
33
33
 
34
34
 
35
35
  class TFKerasModelHandler(DLModelHandler):
@@ -40,8 +40,8 @@ class TFKerasModelHandler(DLModelHandler):
40
40
  # Framework name:
41
41
  FRAMEWORK_NAME = "tensorflow.keras"
42
42
 
43
- # Declare a type of an input sample:
44
- IOSample = Union[tf.Tensor, tf.TensorSpec, np.ndarray]
43
+ # Declare a type of input sample (only from keras v3 there is a KerasTensor type):
44
+ IOSample = Union[tf.Tensor, tf.TensorSpec, "keras.KerasTensor", np.ndarray]
45
45
 
46
46
  class ModelFormats:
47
47
  """
@@ -49,9 +49,19 @@ class TFKerasModelHandler(DLModelHandler):
49
49
  """
50
50
 
51
51
  SAVED_MODEL = "SavedModel"
52
+ KERAS = "keras"
52
53
  H5 = "h5"
53
54
  JSON_ARCHITECTURE_H5_WEIGHTS = "json_h5"
54
55
 
56
+ @classmethod
57
+ def default(cls) -> str:
58
+ """
59
+ Get the default model format to use for saving and loading the model based on the keras version.
60
+
61
+ :return: The default model format to use.
62
+ """
63
+ return cls.KERAS if is_keras_3() else cls.SAVED_MODEL
64
+
55
65
  class _LabelKeys:
56
66
  """
57
67
  Required labels keys to log with the model.
@@ -65,7 +75,7 @@ class TFKerasModelHandler(DLModelHandler):
65
75
  model: keras.Model = None,
66
76
  model_path: Optional[str] = None,
67
77
  model_name: Optional[str] = None,
68
- model_format: str = ModelFormats.SAVED_MODEL,
78
+ model_format: Optional[str] = None,
69
79
  context: mlrun.MLClientCtx = None,
70
80
  modules_map: Optional[
71
81
  Union[dict[str, Union[None, str, list[str]]], str]
@@ -98,7 +108,7 @@ class TFKerasModelHandler(DLModelHandler):
98
108
  * If given a loaded model object and the model name is None, the name will be
99
109
  set to the model's object name / class.
100
110
  :param model_format: The format to use for saving and loading the model. Should be passed as a
101
- member of the class 'ModelFormats'. Default: 'ModelFormats.SAVED_MODEL'.
111
+ member of the class 'ModelFormats'.
102
112
  :param context: MLRun context to work with for logging the model.
103
113
  :param modules_map: A dictionary of all the modules required for loading the model. Each key
104
114
  is a path to a module and its value is the object name to import from it. All
@@ -144,8 +154,11 @@ class TFKerasModelHandler(DLModelHandler):
144
154
  * 'save_traces' parameter was miss-used.
145
155
  """
146
156
  # Validate given format:
157
+ if not model_format:
158
+ model_format = TFKerasModelHandler.ModelFormats.default()
147
159
  if model_format not in [
148
160
  TFKerasModelHandler.ModelFormats.SAVED_MODEL,
161
+ TFKerasModelHandler.ModelFormats.KERAS,
149
162
  TFKerasModelHandler.ModelFormats.H5,
150
163
  TFKerasModelHandler.ModelFormats.JSON_ARCHITECTURE_H5_WEIGHTS,
151
164
  ]:
@@ -153,6 +166,22 @@ class TFKerasModelHandler(DLModelHandler):
153
166
  f"Unrecognized model format: '{model_format}'. Please use one of the class members of "
154
167
  "'TFKerasModelHandler.ModelFormats'"
155
168
  )
169
+ if not is_keras_3():
170
+ if model_format == TFKerasModelHandler.ModelFormats.KERAS:
171
+ raise mlrun.errors.MLRunInvalidArgumentError(
172
+ "The 'keras' model format is only supported in Keras 3.0.0 and above. "
173
+ f"Current version is {keras.__version__}."
174
+ )
175
+ else:
176
+ if (
177
+ model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL
178
+ or model_format
179
+ == TFKerasModelHandler.ModelFormats.JSON_ARCHITECTURE_H5_WEIGHTS
180
+ ):
181
+ raise mlrun.errors.MLRunInvalidArgumentError(
182
+ f"The '{model_format}' model format is not supported in Keras 3.0.0 and above. "
183
+ f"Current version is {keras.__version__}."
184
+ )
156
185
 
157
186
  # Validate 'save_traces':
158
187
  if save_traces:
@@ -239,11 +268,19 @@ class TFKerasModelHandler(DLModelHandler):
239
268
  self._model_file = f"{self._model_name}.h5"
240
269
  self._model.save(self._model_file)
241
270
 
271
+ # ModelFormats.keras - Save as a keras file:
272
+ elif self._model_format == self.ModelFormats.KERAS:
273
+ self._model_file = f"{self._model_name}.keras"
274
+ self._model.save(self._model_file)
275
+
242
276
  # ModelFormats.SAVED_MODEL - Save as a SavedModel directory and zip its file:
243
277
  elif self._model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL:
244
278
  # Save it in a SavedModel format directory:
279
+ # Note: Using keras>=3.0.0 can save in this format via `model.export` but then it won't be able to load it
280
+ # back, only for inference. So, we use the `save` method instead for keras 2 and validate the user won't use
281
+ # keras 3 and this model format.
245
282
  if self._save_traces is True:
246
- # Save traces can only be used in versions >= 2.4, so only if its true we use it in the call:
283
+ # Save traces can only be used in versions >= 2.4, so only if it's true, we use it in the call:
247
284
  self._model.save(self._model_name, save_traces=self._save_traces)
248
285
  else:
249
286
  self._model.save(self._model_name)
@@ -303,6 +340,12 @@ class TFKerasModelHandler(DLModelHandler):
303
340
  self._model_file, custom_objects=self._custom_objects
304
341
  )
305
342
 
343
+ # ModelFormats.KERAS - Load from a keras file:
344
+ elif self._model_format == TFKerasModelHandler.ModelFormats.KERAS:
345
+ self._model = keras.models.load_model(
346
+ self._model_file, custom_objects=self._custom_objects
347
+ )
348
+
306
349
  # ModelFormats.SAVED_MODEL - Load from a SavedModel directory:
307
350
  elif self._model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL:
308
351
  self._model = keras.models.load_model(
@@ -434,7 +477,10 @@ class TFKerasModelHandler(DLModelHandler):
434
477
  )
435
478
 
436
479
  # Read the inputs:
437
- input_signature = [input_layer.type_spec for input_layer in self._model.inputs]
480
+ input_signature = [
481
+ getattr(input_layer, "type_spec", input_layer)
482
+ for input_layer in self._model.inputs
483
+ ]
438
484
 
439
485
  # Set the inputs:
440
486
  self.set_inputs(from_sample=input_signature)
@@ -453,7 +499,8 @@ class TFKerasModelHandler(DLModelHandler):
453
499
 
454
500
  # Read the outputs:
455
501
  output_signature = [
456
- output_layer.type_spec for output_layer in self._model.outputs
502
+ getattr(output_layer, "type_spec", output_layer)
503
+ for output_layer in self._model.outputs
457
504
  ]
458
505
 
459
506
  # Set the outputs:
@@ -509,6 +556,17 @@ class TFKerasModelHandler(DLModelHandler):
509
556
  f"'{self._model_path}'"
510
557
  )
511
558
 
559
+ # ModelFormats.KERAS - Get the keras model file:
560
+ elif self._model_format == TFKerasModelHandler.ModelFormats.KERAS:
561
+ self._model_file = os.path.join(
562
+ self._model_path, f"{self._model_name}.keras"
563
+ )
564
+ if not os.path.exists(self._model_file):
565
+ raise mlrun.errors.MLRunNotFoundError(
566
+ f"The model file '{self._model_name}.keras' was not found within the given 'model_path': "
567
+ f"'{self._model_path}'"
568
+ )
569
+
512
570
  # ModelFormats.SAVED_MODEL - Get the zip file and extract it, or simply locate the directory:
513
571
  elif self._model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL:
514
572
  self._model_file = os.path.join(self._model_path, f"{self._model_name}.zip")
@@ -559,7 +617,9 @@ class TFKerasModelHandler(DLModelHandler):
559
617
  # Supported types:
560
618
  if isinstance(sample, np.ndarray):
561
619
  return super()._read_sample(sample=sample)
562
- elif isinstance(sample, tf.TensorSpec):
620
+ elif isinstance(sample, tf.TensorSpec) or (
621
+ is_keras_3() and isinstance(sample, keras.KerasTensor)
622
+ ):
563
623
  return Feature(
564
624
  name=sample.name,
565
625
  value_type=TFKerasUtils.convert_tf_dtype_to_value_type(
@@ -11,8 +11,8 @@
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
- #
15
14
  import tensorflow as tf
15
+ from packaging import version
16
16
  from tensorflow import keras
17
17
 
18
18
  import mlrun
@@ -117,3 +117,14 @@ class TFKerasUtils(DLUtils):
117
117
  raise mlrun.errors.MLRunInvalidArgumentError(
118
118
  f"MLRun value type is not supporting the given tensorflow data type: '{tf_dtype}'."
119
119
  )
120
+
121
+
122
+ def is_keras_3() -> bool:
123
+ """
124
+ Check if the current Keras version is 3.x.
125
+
126
+ :return: True if Keras version is 3.x, False otherwise.
127
+ """
128
+ return hasattr(keras, "__version__") and version.parse(
129
+ keras.__version__
130
+ ) >= version.parse("3.0.0")
mlrun/launcher/client.py CHANGED
@@ -72,7 +72,7 @@ class ClientBaseLauncher(launcher.BaseLauncher, abc.ABC):
72
72
  ):
73
73
  run.metadata.labels[mlrun_constants.MLRunInternalLabels.kind] = runtime.kind
74
74
  mlrun.runtimes.utils.enrich_run_labels(
75
- run.metadata.labels, [mlrun.common.runtimes.constants.RunLabels.owner]
75
+ run.metadata.labels, [mlrun_constants.MLRunInternalLabels.owner]
76
76
  )
77
77
  if run.spec.output_path:
78
78
  run.spec.output_path = run.spec.output_path.replace(
@@ -11,8 +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
-
15
- import traceback
14
+ import time
16
15
  from collections.abc import Callable
17
16
  from enum import Enum
18
17
  from typing import Any, Final, Optional, Union
@@ -20,6 +19,9 @@ from typing import Any, Final, Optional, Union
20
19
  import taosws
21
20
  from taosws import TaosStmt
22
21
 
22
+ import mlrun
23
+ from mlrun.utils import logger
24
+
23
25
 
24
26
  class _StrEnum(str, Enum):
25
27
  pass
@@ -137,40 +139,99 @@ class Statement:
137
139
  return statement
138
140
 
139
141
 
140
- def _run(connection_string, prefix_statements, q, statements, query):
141
- try:
142
- conn = taosws.connect(connection_string)
143
-
144
- for statement in prefix_statements + statements:
145
- if isinstance(statement, Statement):
146
- prepared_statement = statement.prepare(conn.statement())
147
- prepared_statement.execute()
148
- else:
149
- conn.execute(statement)
150
-
151
- if not query:
152
- q.put(None)
153
- return
154
-
155
- res = conn.query(query)
156
-
157
- # taosws.TaosField is not serializable
158
- fields = [
159
- Field(field.name(), field.type(), field.bytes()) for field in res.fields
160
- ]
161
-
162
- q.put(QueryResult(list(res), fields))
163
- except Exception as e:
164
- tb = traceback.format_exc()
165
- q.put(ErrorResult(tb, e))
166
-
167
-
168
142
  class TDEngineConnection:
169
- def __init__(self, connection_string):
143
+ def __init__(self, connection_string, max_retries=3, retry_delay=0.5):
170
144
  self._connection_string = connection_string
171
145
  self.prefix_statements = []
146
+ self._max_retries = max_retries
147
+ self._retry_delay = retry_delay
172
148
 
173
- self._conn = taosws.connect(self._connection_string)
149
+ self._conn = self._create_connection()
150
+
151
+ def _create_connection(self):
152
+ """Create a new TDEngine connection."""
153
+ return taosws.connect(self._connection_string)
154
+
155
+ def _reconnect(self):
156
+ """Close current connection and create a new one."""
157
+ try:
158
+ if hasattr(self, "_conn") and self._conn:
159
+ self._conn.close()
160
+ except Exception as e:
161
+ logger.warning(f"Error closing connection during reconnect: {e}")
162
+
163
+ self._conn = self._create_connection()
164
+ logger.info("Successfully reconnected to TDEngine")
165
+
166
+ def _execute_with_retry(self, operation, operation_name, *args, **kwargs):
167
+ """
168
+ Execute an operation with retry logic for connection failures.
169
+
170
+ :param operation: The function to execute
171
+ :param operation_name: Name of the operation for logging
172
+ :param args: Arguments to pass to the operation
173
+ :param kwargs: Keyword arguments to pass to the operation
174
+ :return: Result of the operation
175
+ """
176
+ last_exception = None
177
+
178
+ for attempt in range(self._max_retries + 1): # +1 for initial attempt
179
+ try:
180
+ return operation(*args, **kwargs)
181
+
182
+ except taosws.Error as e:
183
+ last_exception = e
184
+
185
+ if attempt < self._max_retries:
186
+ logger.warning(
187
+ f"Connection error during {operation_name} "
188
+ f"(attempt {attempt + 1}/{self._max_retries + 1}): {e}. "
189
+ f"Retrying in {self._retry_delay} seconds..."
190
+ )
191
+
192
+ # Wait before retrying
193
+ time.sleep(self._retry_delay)
194
+
195
+ # Reconnect
196
+ try:
197
+ self._reconnect()
198
+ except Exception as reconnect_error:
199
+ logger.error(f"Failed to reconnect: {reconnect_error}")
200
+ if attempt == self._max_retries - 1:
201
+ # Last attempt, raise the reconnection error
202
+ raise TDEngineError(
203
+ f"Failed to reconnect after {operation_name} failure: {reconnect_error}"
204
+ ) from reconnect_error
205
+ continue
206
+ else:
207
+ # Max retries exceeded
208
+ logger.error(
209
+ f"Max retries ({self._max_retries}) exceeded for {operation_name}"
210
+ )
211
+ break
212
+
213
+ except Exception as e:
214
+ # Non-TDEngine error, don't retry
215
+ raise TDEngineError(
216
+ f"Unexpected error during {operation_name}: {e}"
217
+ ) from e
218
+
219
+ # If we get here, all retries failed
220
+ raise TDEngineError(
221
+ f"Failed to {operation_name} after {self._max_retries} retries: {last_exception}"
222
+ ) from last_exception
223
+
224
+ def _execute_statement(self, statement):
225
+ """Execute a single statement (string or Statement object)."""
226
+ if isinstance(statement, Statement):
227
+ prepared_statement = statement.prepare(self._conn.statement())
228
+ prepared_statement.execute()
229
+ else:
230
+ self._conn.execute(statement)
231
+
232
+ def _execute_query(self, query):
233
+ """Execute a query and return the result."""
234
+ return self._conn.query(query)
174
235
 
175
236
  def run(
176
237
  self,
@@ -181,33 +242,40 @@ class TDEngineConnection:
181
242
  if not isinstance(statements, list):
182
243
  statements = [statements]
183
244
 
184
- for statement in self.prefix_statements + statements:
245
+ # Execute all statements with retry logic
246
+ all_statements = self.prefix_statements + statements
247
+ for i, statement in enumerate(all_statements):
248
+ operation_name = f"execute statement {i + 1}/{len(all_statements)}"
185
249
  if isinstance(statement, Statement):
186
- try:
187
- prepared_statement = statement.prepare(self._conn.statement())
188
- prepared_statement.execute()
189
- except taosws.Error as e:
190
- raise TDEngineError(
191
- f"Failed to run prepared statement `{self._conn.statement()}`: {e}"
192
- ) from e
250
+ operation_name += " (prepared)"
193
251
  else:
194
- try:
195
- self._conn.execute(statement)
196
- except taosws.Error as e:
197
- raise TDEngineError(
198
- f"Failed to run statement `{statement}`: {e}"
199
- ) from e
252
+ operation_name += f" `{statement}`"
253
+
254
+ self._execute_with_retry(self._execute_statement, operation_name, statement)
200
255
 
201
256
  if not query:
202
257
  return None
203
258
 
204
- try:
205
- res = self._conn.query(query)
206
- except taosws.Error as e:
207
- raise TDEngineError(f"Failed to run query `{query}`: {e}") from e
259
+ # Execute query with retry logic
260
+ res = self._execute_with_retry(
261
+ self._execute_query, f"execute query `{query}`", query
262
+ )
208
263
 
264
+ # Process results
209
265
  fields = [
210
266
  Field(field.name(), field.type(), field.bytes()) for field in res.fields
211
267
  ]
212
268
 
213
269
  return QueryResult(list(res), fields)
270
+
271
+ def close(self):
272
+ """Close the connection."""
273
+ try:
274
+ if self._conn:
275
+ self._conn.close()
276
+ logger.debug("TDEngine connection closed")
277
+ self._conn = None
278
+ except Exception as e:
279
+ logger.warning(
280
+ f"Error closing TDEngine connection: {mlrun.errors.err_to_str(e)}"
281
+ )
@@ -12,8 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import threading
15
16
  from datetime import datetime, timedelta
16
- from threading import Lock
17
17
  from typing import Callable, Final, Literal, Optional, Union
18
18
 
19
19
  import pandas as pd
@@ -32,8 +32,8 @@ from mlrun.model_monitoring.db.tsdb.tdengine.tdengine_connection import (
32
32
  from mlrun.model_monitoring.helpers import get_invocations_fqn
33
33
  from mlrun.utils import logger
34
34
 
35
- _connection = None
36
- _connection_lock = Lock()
35
+ # Thread-local storage for connections
36
+ _thread_local = threading.local()
37
37
 
38
38
 
39
39
  class TDEngineTimestampPrecision(mlrun.common.types.StrEnum):
@@ -76,16 +76,15 @@ class TDEngineConnector(TSDBConnector):
76
76
 
77
77
  @property
78
78
  def connection(self) -> TDEngineConnection:
79
- global _connection
80
-
81
- if _connection:
82
- return _connection
83
-
84
- with _connection_lock:
85
- if not _connection:
86
- _connection = self._create_connection()
87
-
88
- return _connection
79
+ if not hasattr(_thread_local, "connection"):
80
+ _thread_local.connection = self._create_connection()
81
+ logger.debug(
82
+ "Created new TDEngine connection for thread",
83
+ project=self.project,
84
+ thread_name=threading.current_thread().name,
85
+ thread_id=threading.get_ident(),
86
+ )
87
+ return _thread_local.connection
89
88
 
90
89
  def _create_connection(self) -> TDEngineConnection:
91
90
  """Establish a connection to the TSDB server."""
mlrun/projects/project.py CHANGED
@@ -1408,7 +1408,10 @@ class MlrunProject(ModelObj):
1408
1408
  https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html#module-apscheduler.triggers.cron
1409
1409
  Note that "local" engine does not support this argument
1410
1410
  :param ttl: Pipeline ttl in secs (after that the pods will be removed)
1411
- :param image: Image for workflow runner job, only for scheduled and remote workflows
1411
+ :param image: Image for workflow runner job, only for scheduled and remote workflows.
1412
+ The image must have mlrun[kfp] installed which requires python 3.9.
1413
+ Therefore, the project default image will not be used for the workflow,
1414
+ and the image must be specified explicitly.
1412
1415
  :param args: Argument values (key=value, ..)
1413
1416
  """
1414
1417
 
mlrun/runtimes/base.py CHANGED
@@ -489,7 +489,7 @@ class BaseRuntime(ModelObj):
489
489
  def _store_function(self, runspec, meta, db):
490
490
  meta.labels["kind"] = self.kind
491
491
  mlrun.runtimes.utils.enrich_run_labels(
492
- meta.labels, [mlrun.common.runtimes.constants.RunLabels.owner]
492
+ meta.labels, [mlrun_constants.MLRunInternalLabels.owner]
493
493
  )
494
494
  if runspec.spec.output_path:
495
495
  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(),
446
+ mlrun_constants.MLRunInternalLabels.owner: os.environ.get("V3IO_USERNAME")
447
+ or getpass.getuser(),
440
448
  # TODO: remove this in 1.10.0
441
- RunLabels.v3io_user: os.environ.get("V3IO_USERNAME"),
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
 
@@ -384,15 +384,15 @@ class V2ModelServer(StepToDict):
384
384
  return event
385
385
 
386
386
  def logged_results(self, request: dict, response: dict, op: str):
387
- """hook for controlling which results are tracked by the model monitoring
387
+ """Hook for controlling which results are tracked by the model monitoring
388
388
 
389
- this hook allows controlling which input/output data is logged by the model monitoring
390
- allow filtering out columns or adding custom values, can also be used to monitor derived metrics
391
- for example in image classification calculate and track the RGB values vs the image bitmap
389
+ This hook allows controlling which input/output data is logged by the model monitoring.
390
+ It allows filtering out columns or adding custom values, and can also be used to monitor derived metrics,
391
+ for example in image classification to calculate and track the RGB values vs the image bitmap.
392
392
 
393
- the request["inputs"] holds a list of input values/arrays, the response["outputs"] holds a list of
394
- corresponding output values/arrays (the schema of the input/output fields is stored in the model object),
395
- this method should return lists of alternative inputs and outputs which will be monitored
393
+ The request ["inputs"] holds a list of input values/arrays, the response ["outputs"] holds a list of
394
+ corresponding output values/arrays (the schema of the input/output fields is stored in the model object).
395
+ This method should return lists of alternative inputs and outputs which will be monitored.
396
396
 
397
397
  :param request: predict/explain request, see model serving docs for details
398
398
  :param response: result from the model predict/explain (after postprocess())
@@ -422,6 +422,7 @@ class V2ModelServer(StepToDict):
422
422
 
423
423
  def predict(self, request: dict) -> list:
424
424
  """model prediction operation
425
+
425
426
  :return: list with the model prediction results (can be multi-port) or list of lists for multiple predictions
426
427
  """
427
428
  raise NotImplementedError()
@@ -436,7 +437,7 @@ class V2ModelServer(StepToDict):
436
437
  where the internal list order is according to the ArtifactModel inputs.
437
438
 
438
439
  :param request: event
439
- :return: evnet body converting the inputs to be list of lists
440
+ :return: event body converting the inputs to be list of lists
440
441
  """
441
442
  if self.model_spec and self.model_spec.inputs:
442
443
  input_order = [feature.name for feature in self.model_spec.inputs]
mlrun/utils/helpers.py CHANGED
@@ -876,16 +876,25 @@ def enrich_image_url(
876
876
  client_version: Optional[str] = None,
877
877
  client_python_version: Optional[str] = None,
878
878
  ) -> str:
879
+ image_url = image_url.strip()
880
+
881
+ # Add python version tag if needed
882
+ if image_url == "python" and client_python_version:
883
+ image_tag = ".".join(client_python_version.split(".")[:2])
884
+ image_url = f"python:{image_tag}"
885
+
879
886
  client_version = _convert_python_package_version_to_image_tag(client_version)
880
887
  server_version = _convert_python_package_version_to_image_tag(
881
888
  mlrun.utils.version.Version().get()["version"]
882
889
  )
883
- image_url = image_url.strip()
884
890
  mlrun_version = config.images_tag or client_version or server_version
885
- tag = mlrun_version
886
- tag += resolve_image_tag_suffix(
887
- mlrun_version=mlrun_version, python_version=client_python_version
888
- )
891
+ tag = mlrun_version or ""
892
+
893
+ # TODO: Remove condition when mlrun/mlrun-kfp image is also supported
894
+ if "mlrun-kfp" not in image_url:
895
+ tag += resolve_image_tag_suffix(
896
+ mlrun_version=mlrun_version, python_version=client_python_version
897
+ )
889
898
 
890
899
  # it's an mlrun image if the repository is mlrun
891
900
  is_mlrun_image = image_url.startswith("mlrun/") or "/mlrun/" in image_url
@@ -917,7 +926,7 @@ def resolve_image_tag_suffix(
917
926
  mlrun_version: Optional[str] = None, python_version: Optional[str] = None
918
927
  ) -> str:
919
928
  """
920
- resolves what suffix should be appended to the image tag
929
+ Resolves what suffix to be appended to the image tag
921
930
  :param mlrun_version: the mlrun version
922
931
  :param python_version: the requested python version
923
932
  :return: the suffix to append to the image tag
@@ -929,19 +938,19 @@ def resolve_image_tag_suffix(
929
938
  # mlrun version is higher than 1.3.0, but we can check the python version and if python version was passed it
930
939
  # means it 1.3.0-rc or higher, so we can add the suffix of the python version.
931
940
  if mlrun_version.startswith("0.0.0-") or "unstable" in mlrun_version:
932
- if python_version.startswith("3.7"):
933
- return "-py37"
941
+ if python_version.startswith("3.9"):
942
+ return "-py39"
934
943
  return ""
935
944
 
936
- # For mlrun 1.3.x and 1.4.x, we support mlrun runtimes images with both python 3.7 and 3.9 images.
937
- # While the python 3.9 images will continue to have no suffix, the python 3.7 images will have a '-py37' suffix.
938
- # Python 3.8 images will not be supported for mlrun 1.3.0, meaning that if the user has client with python 3.8
939
- # and mlrun 1.3.x then the image will be pulled without a suffix (which is the python 3.9 image).
945
+ # For mlrun 1.9.x and 1.10.x, we support mlrun runtimes images with both python 3.9 and 3.11 images.
946
+ # While the python 3.11 images will continue to have no suffix, the python 3.9 images will have a '-py39' suffix.
947
+ # Python 3.10 images are not supported in mlrun 1.9.0, meaning that if the user has client with python 3.10
948
+ # and mlrun 1.9.x then the image will be pulled without a suffix (which is the python 3.11 image).
940
949
  # using semver (x.y.z-X) to include rc versions as well
941
- if semver.VersionInfo.parse("1.5.0-X") > semver.VersionInfo.parse(
950
+ if semver.VersionInfo.parse("1.11.0-X") > semver.VersionInfo.parse(
942
951
  mlrun_version
943
- ) >= semver.VersionInfo.parse("1.3.0-X") and python_version.startswith("3.7"):
944
- return "-py37"
952
+ ) >= semver.VersionInfo.parse("1.9.0-X") and python_version.startswith("3.9"):
953
+ return "-py39"
945
954
  return ""
946
955
 
947
956
 
@@ -2254,7 +2263,10 @@ class Workflow:
2254
2263
  def _get_workflow_manifest(
2255
2264
  workflow_id: str,
2256
2265
  ) -> typing.Optional[mlrun_pipelines.models.PipelineManifest]:
2257
- kfp_client = mlrun_pipelines.utils.get_client(mlrun.mlconf.kfp_url)
2266
+ kfp_client = mlrun_pipelines.utils.get_client(
2267
+ url=mlrun.mlconf.kfp_url,
2268
+ namespace=mlrun.mlconf.namespace,
2269
+ )
2258
2270
 
2259
2271
  # arbitrary timeout of 30 seconds, the workflow should be done by now, however sometimes kfp takes a few
2260
2272
  # seconds to update the workflow status
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "bd76eb04427505ad0944a97ddcf76e50820cce32",
3
- "version": "1.8.0-rc62"
2
+ "git_commit": "f36cbb4f1a9a264471b1fa40a453b382d056988a",
3
+ "version": "1.9.0"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlrun
3
- Version: 1.8.0rc62
3
+ Version: 1.9.0
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -15,6 +15,7 @@ Classifier: Operating System :: Microsoft :: Windows
15
15
  Classifier: Operating System :: MacOS
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python
19
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
21
  Classifier: Topic :: Software Development :: Libraries
@@ -35,7 +36,7 @@ Requires-Dist: pyarrow<17,>=10.0
35
36
  Requires-Dist: pyyaml<7,>=6.0.2
36
37
  Requires-Dist: requests~=2.32
37
38
  Requires-Dist: tabulate~=0.8.6
38
- Requires-Dist: v3io~=0.6.9
39
+ Requires-Dist: v3io~=0.7.0
39
40
  Requires-Dist: pydantic>=1.10.15
40
41
  Requires-Dist: mergedeep~=1.3
41
42
  Requires-Dist: v3io-frames~=0.10.14; python_version < "3.11"
@@ -44,15 +45,15 @@ Requires-Dist: semver~=3.0
44
45
  Requires-Dist: dependency-injector~=4.41
45
46
  Requires-Dist: fsspec<2024.7,>=2023.9.2
46
47
  Requires-Dist: v3iofs~=0.1.17
47
- Requires-Dist: storey~=1.8.11
48
+ Requires-Dist: storey~=1.9.0
48
49
  Requires-Dist: inflection~=0.5.0
49
50
  Requires-Dist: python-dotenv~=1.0
50
51
  Requires-Dist: setuptools>=75.2
51
52
  Requires-Dist: deprecated~=1.2
52
53
  Requires-Dist: jinja2>=3.1.3,~=3.1
53
54
  Requires-Dist: orjson<4,>=3.9.15
54
- Requires-Dist: mlrun-pipelines-kfp-common~=0.3.15
55
- Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.3.10; python_version < "3.11"
55
+ Requires-Dist: mlrun-pipelines-kfp-common~=0.4.4
56
+ Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.4.3
56
57
  Requires-Dist: docstring_parser~=0.16
57
58
  Requires-Dist: aiosmtplib~=3.0
58
59
  Provides-Extra: s3
@@ -102,7 +103,7 @@ Requires-Dist: taos-ws-py==0.3.2; extra == "tdengine"
102
103
  Provides-Extra: snowflake
103
104
  Requires-Dist: snowflake-connector-python~=3.7; extra == "snowflake"
104
105
  Provides-Extra: kfp18
105
- Requires-Dist: mlrun_pipelines_kfp_v1_8[kfp]>=0.3.2; python_version < "3.11" and extra == "kfp18"
106
+ Requires-Dist: mlrun_pipelines_kfp_v1_8[kfp]>=0.4.0; python_version < "3.11" and extra == "kfp18"
106
107
  Provides-Extra: api
107
108
  Requires-Dist: uvicorn~=0.32.1; extra == "api"
108
109
  Requires-Dist: dask-kubernetes~=0.11.0; extra == "api"
@@ -118,7 +119,7 @@ Requires-Dist: timelength~=1.1; extra == "api"
118
119
  Requires-Dist: memray~=1.12; sys_platform != "win32" and extra == "api"
119
120
  Requires-Dist: aiosmtplib~=3.0; extra == "api"
120
121
  Requires-Dist: pydantic<2,>=1; extra == "api"
121
- Requires-Dist: mlrun-pipelines-kfp-v1-8[kfp]~=0.3.10; python_version < "3.11" and extra == "api"
122
+ Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.4.3; extra == "api"
122
123
  Requires-Dist: grpcio~=1.70.0; extra == "api"
123
124
  Provides-Extra: all
124
125
  Requires-Dist: adlfs==2023.9.0; extra == "all"
@@ -212,7 +213,7 @@ Requires-Dist: igz-mgmt~=0.4.1; extra == "complete-api"
212
213
  Requires-Dist: kafka-python~=2.1.0; extra == "complete-api"
213
214
  Requires-Dist: memray~=1.12; sys_platform != "win32" and extra == "complete-api"
214
215
  Requires-Dist: mlflow~=2.16; extra == "complete-api"
215
- Requires-Dist: mlrun-pipelines-kfp-v1-8[kfp]~=0.3.10; python_version < "3.11" and extra == "complete-api"
216
+ Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.4.3; extra == "complete-api"
216
217
  Requires-Dist: msrest~=0.6.21; extra == "complete-api"
217
218
  Requires-Dist: objgraph~=3.6; extra == "complete-api"
218
219
  Requires-Dist: oss2==2.18.1; extra == "complete-api"
@@ -1,6 +1,6 @@
1
1
  mlrun/__init__.py,sha256=Cqm9U9eCEdLpMejhU2BEhubu0mHL71igJJIwYa738EA,7450
2
- mlrun/__main__.py,sha256=0NDzPf9VFRO8KFfGgb8mkGUPIDS285aASV8Hbxs-ND0,45920
3
- mlrun/config.py,sha256=xxmIe0g1YP2Y5_R_uQjP3w6v_4lA7iTjXhAyojdY08I,71929
2
+ mlrun/__main__.py,sha256=ktsoMxLmW65ABu5oG7TbUJvusyAYy_PRollQOGj4cGY,46352
3
+ mlrun/config.py,sha256=R8RDtYt2EZ4lU-H_oi8cSx52Zw33C92MBe9Lv4JqHl8,71933
4
4
  mlrun/errors.py,sha256=LkcbXTLANGdsgo2CRX2pdbyNmt--lMsjGv0XZMgP-Nc,8222
5
5
  mlrun/execution.py,sha256=rss4zA5M9tOCnSaXrK_-_BQ5F5DfF9OzesgQliq7jvQ,50008
6
6
  mlrun/features.py,sha256=ReBaNGsBYXqcbgI012n-SO_j6oHIbk_Vpv0CGPXbUmo,15842
@@ -21,7 +21,7 @@ mlrun/artifacts/manager.py,sha256=bqp2-VgThx5RAGEui6LwTA9EMNNq6Vu1Z_-yjBpk92c,16
21
21
  mlrun/artifacts/model.py,sha256=J5b8zODrpx5ULtsgS9RGKqzMXYs7ADacE0BLBglmhrs,22239
22
22
  mlrun/artifacts/plots.py,sha256=TxOHBaGbj7fEKNTHVIM_uxQjqPLpU3Rh1pqGh2_inuo,4833
23
23
  mlrun/common/__init__.py,sha256=xY3wHC4TEJgez7qtnn1pQvHosi8-5UJOCtyGBS7FcGE,571
24
- mlrun/common/constants.py,sha256=14xMUX9C5BB-LxsTlMTJQf_Xz2DyRjaK9yeR5dadcDU,3426
24
+ mlrun/common/constants.py,sha256=Yj5YHANbpKHDKxZ1y5bV1wifvV3UQZ2QuvECUuYhrpM,3594
25
25
  mlrun/common/helpers.py,sha256=DIdqs_eN3gO5bZ8iFobIvx8cEiOxYxhFIyut6-O69T0,1385
26
26
  mlrun/common/secrets.py,sha256=vc8WV82EZsCB5ENjUkObFOzZP59aZ1w8F82PTnqwBnc,5181
27
27
  mlrun/common/types.py,sha256=1gxThbmC0Vd0U1ffIkEwz4T4S7JOgHt70rvw8TCO21c,1073
@@ -86,7 +86,7 @@ mlrun/datastore/alibaba_oss.py,sha256=k-OHVe08HjMewlkpsT657CbOiVFAfSq9_EqhCE-k86
86
86
  mlrun/datastore/azure_blob.py,sha256=SzAcHYSXkm8Zpopz2Ea-rWVClH0URocUazcNK04S9W0,12776
87
87
  mlrun/datastore/base.py,sha256=9R3lwB_L4hv5WW2q24WS62_KTh-wO4UG6pwzISZU6bM,26231
88
88
  mlrun/datastore/datastore.py,sha256=AXXPgHpSG8Ig1RtTDGfdCJu4UT-AQPC43FGBOptIVOg,9484
89
- mlrun/datastore/datastore_profile.py,sha256=JIH7GYlC40pdaqO8xwYp52dO8QFEB8le021kFINFh4k,23862
89
+ mlrun/datastore/datastore_profile.py,sha256=ywIFYRzMWgb510GuRBDhsJvUbkPENl2qUDQbIBifuWE,23865
90
90
  mlrun/datastore/dbfs_store.py,sha256=QkDRzwFnvm7CgEg4NuGxes6tBgKDyhX0CiBUvK8c9pk,6568
91
91
  mlrun/datastore/filestore.py,sha256=OcykjzhbUAZ6_Cb9bGAXRL2ngsOpxXSb4rR0lyogZtM,3773
92
92
  mlrun/datastore/google_cloud_storage.py,sha256=MnToY6irdhBZ8Wcapqnr1Yq2724LAh2uPO7MAtdWfUY,8716
@@ -110,7 +110,7 @@ mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
110
110
  mlrun/db/auth_utils.py,sha256=hpg8D2r82oN0BWabuWN04BTNZ7jYMAF242YSUpK7LFM,5211
111
111
  mlrun/db/base.py,sha256=lfPEPUBXPdmzXUhFD0hDBBWXdV7HXfcsz9Gj_AMLllg,30819
112
112
  mlrun/db/factory.py,sha256=yP2vVmveUE7LYTCHbS6lQIxP9rW--zdISWuPd_I3d_4,2111
113
- mlrun/db/httpdb.py,sha256=p2IIJxkc_q3xAKymIzX3Ic3ep60X6bpQ6PZRe9s0fyY,232763
113
+ mlrun/db/httpdb.py,sha256=AxfZuJQJl8yGv9rt2pPOPMrDik3bZ73gbdyEfeEZvyM,232833
114
114
  mlrun/db/nopdb.py,sha256=ttC1pe95rZdMgiLG9kzrjZFYB1gWj3SEqeqK5c0q0w4,27197
115
115
  mlrun/feature_store/__init__.py,sha256=SlI845bWt6xX34SXunHHqhmFAR9-5v2ak8N-qpcAPGo,1328
116
116
  mlrun/feature_store/api.py,sha256=qKj5Tk6prTab6XWatWhBuPRVp0eJEctoxRMN2wz48vA,32168
@@ -198,13 +198,13 @@ mlrun/frameworks/sklearn/metrics_library.py,sha256=PVPNpljaGglXcw7THLHX-XU0cA8Nu
198
198
  mlrun/frameworks/sklearn/mlrun_interface.py,sha256=JzHMBQM4sPBJqzb8P-rsG_2RQ_QrXrb8KFj6GNfwrJ0,14339
199
199
  mlrun/frameworks/sklearn/model_handler.py,sha256=n0vpsQznva_WVloz7GTnfMGcMDQU_f1bHhUAJ_qxjfE,4753
200
200
  mlrun/frameworks/sklearn/utils.py,sha256=Cg_pSxUMvKe8vBSLQor6JM8u9_ccKJg4Rk5EPDzTsVo,1209
201
- mlrun/frameworks/tf_keras/__init__.py,sha256=OIHqn6Y1_lcB2j5O3hKea4cp0uVtF4Lv96lvAkm_9x4,10553
201
+ mlrun/frameworks/tf_keras/__init__.py,sha256=M2sMbYHLrlF-KFR5kvA9mevRo3Nf8U0B5a_DM9rzwCY,10484
202
202
  mlrun/frameworks/tf_keras/mlrun_interface.py,sha256=1xPUv8YAqxrY3CmkMfWMdp2yEAvk5viiMH6qw41ytSk,16617
203
- mlrun/frameworks/tf_keras/model_handler.py,sha256=K99NF7WxqmGpzXXssO9mdQb_Swaek_g3aIhZ4GW-k1k,28276
203
+ mlrun/frameworks/tf_keras/model_handler.py,sha256=CquUawDowzZgbQtphFbdz1QBzNlOfnnePSHkHDS9Iqg,31102
204
204
  mlrun/frameworks/tf_keras/model_server.py,sha256=PZW6OBGTJ6bSfHedAhhW8HATbJyp2VaAzSDC02zjyKk,9653
205
- mlrun/frameworks/tf_keras/utils.py,sha256=_QWk1YmdRybbUB54vsQFE2_WMuAK0g7eR1ozVbMk0Go,4284
205
+ mlrun/frameworks/tf_keras/utils.py,sha256=Z8hA1CgpSJWLC_T6Ay7xZKVyWlX9B85MSmQr2biXRag,4582
206
206
  mlrun/frameworks/tf_keras/callbacks/__init__.py,sha256=sd8aWG2jO9mO_noZca0ReVf8X6fSCqO_di1Z-mT8FH8,742
207
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py,sha256=QGgCDAVtoixy94NdrbCfQLsV0kQlv4b535pVv47RRRw,22029
207
+ mlrun/frameworks/tf_keras/callbacks/logging_callback.py,sha256=0-cwQU-GIPUnHRqez9MX4_Gwgb6OgdcPRjU6E2Xo5JE,22323
208
208
  mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py,sha256=O63ZL_04wqxDHhDsNhGX880dUmIUPt5bKnSgTUTbduw,8838
209
209
  mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py,sha256=Z0Qgea9-G0-9gq3OPH3Cre7f8zMWX0bWyBQPgxxemYQ,28616
210
210
  mlrun/frameworks/xgboost/__init__.py,sha256=NyFRxu5v5z8oegbJP05PFUmfJL3I3JeN1PYHjIbfXpo,10335
@@ -213,7 +213,7 @@ mlrun/frameworks/xgboost/model_handler.py,sha256=e3VLKMmaC9OFoclUPx9buUXYLDe1Ab3
213
213
  mlrun/frameworks/xgboost/utils.py,sha256=5zLzHoeI3n2FuA_rdGzi404QCTLfQx1TYEyUWhZogs8,1069
214
214
  mlrun/launcher/__init__.py,sha256=JL8qkT1lLr1YvW6iP0hmwDTaSR2RfrMDx0-1gWRhTOE,571
215
215
  mlrun/launcher/base.py,sha256=uZaUpwjy9_Z137aQ4b1JsuYqD01ZVRxytAxZSFKSu6U,16480
216
- mlrun/launcher/client.py,sha256=lJ3y9brmPspgwAZrUPAeu3Dn5B7mh9k3MhrbFKhNDvw,6286
216
+ mlrun/launcher/client.py,sha256=iZS5rqIf2do1XNGJ4oyQHkdQtndr48l9Mffs_xCI_NI,6280
217
217
  mlrun/launcher/factory.py,sha256=RW7mfzEFi8fR0M-4W1JQg1iq3_muUU6OTqT_3l4Ubrk,2338
218
218
  mlrun/launcher/local.py,sha256=775HY-8S9LFUX5ubGXrLO0N1lVh8bn-DHFmNYuNqQPA,11451
219
219
  mlrun/launcher/remote.py,sha256=rLJW4UAnUT5iUb4BsGBOAV3K4R29a0X4lFtRkVKlyYU,7709
@@ -242,8 +242,8 @@ mlrun/model_monitoring/db/tsdb/helpers.py,sha256=0oUXc4aUkYtP2SGP6jTb3uPPKImIUsV
242
242
  mlrun/model_monitoring/db/tsdb/tdengine/__init__.py,sha256=vgBdsKaXUURKqIf3M0y4sRatmSVA4CQiJs7J5dcVBkQ,620
243
243
  mlrun/model_monitoring/db/tsdb/tdengine/schemas.py,sha256=EslhaR65jfeNdD5Ibk-3Hb4e5r5qYPfHb9rTChX3sG0,12689
244
244
  mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py,sha256=Uadj0UvAmln2MxDWod-kAzau1uNlqZh981rPhbUH_5M,2857
245
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py,sha256=8xo2O_yQrJGNDoYYB3Bwtdwwvzs3U9dT3BtPot0zENQ,6449
246
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=h0ZrNgOwTlBRd_DaYDc6eeVM9f_8CLJMUPEAIrZpbyU,37803
245
+ mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py,sha256=dtkaHaWKWERPXylEWMECeetwrz3rWl0P43AADcTjlls,9330
246
+ mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=f-3bycfwGvu7gX_Jh3vRT-s2k_yZRXLeIkBrt11xTdc,37998
247
247
  mlrun/model_monitoring/db/tsdb/v3io/__init__.py,sha256=aL3bfmQsUQ-sbvKGdNihFj8gLCK3mSys0qDcXtYOwgc,616
248
248
  mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py,sha256=_-zo9relCDtjGgievxAcAP9gVN9nDWs8BzGtFwTjb9M,6284
249
249
  mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py,sha256=aDdyHWJLOG-3EgPTJgbEzOOQf5NetpFQk_HdQbs5_zI,47160
@@ -271,9 +271,9 @@ mlrun/platforms/iguazio.py,sha256=6VBTq8eQ3mzT96tzjYhAtcMQ2VjF4x8LpIPW5DAcX2Q,13
271
271
  mlrun/projects/__init__.py,sha256=0Krf0WIKfnZa71WthYOg0SoaTodGg3sV_hK3f_OlTPI,1220
272
272
  mlrun/projects/operations.py,sha256=9ntpM8WnnyRk1iCY0NDKW-3aR4j2QZPSJM0SdMnsQKs,20032
273
273
  mlrun/projects/pipelines.py,sha256=wud7ezeEmhIJvfYE_wzQbA4ygEfGXHtbOtoOpan6poY,48556
274
- mlrun/projects/project.py,sha256=O3oeg5ZZLvsvftN_T6syB1xQJ7e1eFg37mrlIaL4VCY,237075
274
+ mlrun/projects/project.py,sha256=VY9Wd1GfMH8CUUdOPN9UDsmcvsddlB_HYd2abodvSXY,237350
275
275
  mlrun/runtimes/__init__.py,sha256=J9Sy2HiyMlztNv6VUurMzF5H2XzttNil8nRsWDsqLyg,8923
276
- mlrun/runtimes/base.py,sha256=m347abcZRdI8654wBJea9D2GBRlkv_prz9UrA5ihlkA,37859
276
+ mlrun/runtimes/base.py,sha256=K-38p2HYSpaPcenJgEzQqLlLVFxfwLu2Bwe9oXGWCTM,37853
277
277
  mlrun/runtimes/daskjob.py,sha256=JwuGvOiPsxEDHHMMUS4Oie4hLlYYIZwihAl6DjroTY0,19521
278
278
  mlrun/runtimes/funcdoc.py,sha256=zRFHrJsV8rhDLJwoUhcfZ7Cs0j-tQ76DxwUqdXV_Wyc,9810
279
279
  mlrun/runtimes/function_reference.py,sha256=fnMKUEieKgy4JyVLhFpDtr6JvKgOaQP8F_K2H3-Pk9U,5030
@@ -283,7 +283,7 @@ mlrun/runtimes/local.py,sha256=yedo3R1c46cB1mX7aOz8zORXswQPvX86U-_fYxXoqTY,22717
283
283
  mlrun/runtimes/mounts.py,sha256=2dkoktm3TXHe4XHmRhvC0UfvWzq2vy_13MeaW7wgyPo,18735
284
284
  mlrun/runtimes/pod.py,sha256=kjnDKOQKqfmprzA3tbXhaB58Dp6So4cOApcjYZ3kVko,67691
285
285
  mlrun/runtimes/remotesparkjob.py,sha256=dod99nqz3GdRfmnBoQKfwFCXTetfuCScd2pKH3HJyoY,7394
286
- mlrun/runtimes/utils.py,sha256=ut0IvQr47NI4Tw7XeHrA7HU7Zun3B1-K44GInecSWF8,15676
286
+ mlrun/runtimes/utils.py,sha256=VFKA7dWuILAcJGia_7Pw_zBBG00wZlat7o2N6u5EItw,16284
287
287
  mlrun/runtimes/databricks_job/__init__.py,sha256=kXGBqhLN0rlAx0kTXhozGzFsIdSqW0uTSKMmsLgq_is,569
288
288
  mlrun/runtimes/databricks_job/databricks_cancel_task.py,sha256=sIqIg5DQAf4j0wCPA-G0GoxY6vacRddxCy5KDUZszek,2245
289
289
  mlrun/runtimes/databricks_job/databricks_runtime.py,sha256=WBq8Q0RIYwLkyshU7btYrB59wotzK_6xixHqZ-oz0PY,12851
@@ -310,7 +310,7 @@ mlrun/serving/serving_wrapper.py,sha256=R670-S6PX_d5ER6jiHtRvacuPyFzQH0mEf2K0sBI
310
310
  mlrun/serving/states.py,sha256=PaVdgZ8GyE8bxr_-RvuSUINwHuPypJmqaQs27aEPweo,73367
311
311
  mlrun/serving/utils.py,sha256=k2EIYDWHUGkE-IBI6T0UNT32fw-KySsccIJM_LObI00,4171
312
312
  mlrun/serving/v1_serving.py,sha256=c6J_MtpE-Tqu00-6r4eJOCO6rUasHDal9W2eBIcrl50,11853
313
- mlrun/serving/v2_serving.py,sha256=b3C5Utv2_AOPrH_hPi3NarjNbAK3kRoeIfqMU4qNuUo,25362
313
+ mlrun/serving/v2_serving.py,sha256=kVagsCxjRKzdoj-0PNFOg5iI4ub1EYpvlZkULvo-8pw,25380
314
314
  mlrun/track/__init__.py,sha256=yVXbT52fXvGKRlc_ByHqIVt7-9L3DRE634RSeQwgXtU,665
315
315
  mlrun/track/tracker.py,sha256=CyTU6Qd3_5GGEJ_hpocOj71wvV65EuFYUjaYEUKAL6Q,3575
316
316
  mlrun/track/tracker_manager.py,sha256=IYBl99I62IC6VCCmG1yt6JoHNOQXa53C4DURJ2sWgio,5726
@@ -322,7 +322,7 @@ mlrun/utils/azure_vault.py,sha256=IEFizrDGDbAaoWwDr1WoA88S_EZ0T--vjYtY-i0cvYQ,34
322
322
  mlrun/utils/clones.py,sha256=yXOeuLtgIiKZdmjeKK0Z_vIrH19ds5JuoJaCeDjhwOo,7516
323
323
  mlrun/utils/condition_evaluator.py,sha256=-nGfRmZzivn01rHTroiGY4rqEv8T1irMyhzxEei-sKc,1897
324
324
  mlrun/utils/db.py,sha256=blQgkWMfFH9lcN4sgJQcPQgEETz2Dl_zwbVA0SslpFg,2186
325
- mlrun/utils/helpers.py,sha256=m5WwqAjneDiF0k9YKBwcwqdE-z0oWd-_4mZvYlNJa18,78461
325
+ mlrun/utils/helpers.py,sha256=ED6uhiximgL9_StrXWnfDNn5uAQFDGIHFOmvQddK6KE,78868
326
326
  mlrun/utils/http.py,sha256=t6FrXQstZm9xVVjxqIGiLzrwZNCR4CSienSOuVgNIcI,8706
327
327
  mlrun/utils/logger.py,sha256=RG0m1rx6gfkJ-2C1r_p41MMpPiaDYqaYM2lYHDlNZEU,14767
328
328
  mlrun/utils/regex.py,sha256=jbR7IiOp6OO0mg9Fl_cVZCpWb9fL9nTPONCUxCDNWXg,5201
@@ -341,11 +341,11 @@ mlrun/utils/notifications/notification/mail.py,sha256=ZyJ3eqd8simxffQmXzqd3bgbAq
341
341
  mlrun/utils/notifications/notification/slack.py,sha256=kfhogR5keR7Zjh0VCjJNK3NR5_yXT7Cv-x9GdOUW4Z8,7294
342
342
  mlrun/utils/notifications/notification/webhook.py,sha256=zxh8CAlbPnTazsk6r05X5TKwqUZVOH5KBU2fJbzQlG4,5330
343
343
  mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
344
- mlrun/utils/version/version.json,sha256=pftUvz4mfka5ERnvT8qp-923vew4A898akorrF6GIK0,89
344
+ mlrun/utils/version/version.json,sha256=EJ4rtjC3_V0pmJXOcoc2LI3XUF5zyqW2FLmw_PjLKlc,84
345
345
  mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
346
- mlrun-1.8.0rc62.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
347
- mlrun-1.8.0rc62.dist-info/METADATA,sha256=_qTx4TQ65fT8WIQ-NuWfELnelYX5HsR-12CEXfcizaU,25805
348
- mlrun-1.8.0rc62.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
349
- mlrun-1.8.0rc62.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
350
- mlrun-1.8.0rc62.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
351
- mlrun-1.8.0rc62.dist-info/RECORD,,
346
+ mlrun-1.9.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
347
+ mlrun-1.9.0.dist-info/METADATA,sha256=ulIL0BTmyTEMCClGlH9WA4ZO5-riMYqnCM7FFzVL-Mo,25756
348
+ mlrun-1.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
349
+ mlrun-1.9.0.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
350
+ mlrun-1.9.0.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
351
+ mlrun-1.9.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5