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 +13 -3
- mlrun/common/constants.py +7 -0
- mlrun/config.py +3 -3
- mlrun/datastore/datastore_profile.py +3 -3
- mlrun/db/httpdb.py +4 -2
- mlrun/frameworks/tf_keras/__init__.py +4 -4
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +23 -20
- mlrun/frameworks/tf_keras/model_handler.py +69 -9
- mlrun/frameworks/tf_keras/utils.py +12 -1
- mlrun/launcher/client.py +1 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +118 -50
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +12 -13
- mlrun/projects/project.py +4 -1
- mlrun/runtimes/base.py +1 -1
- mlrun/runtimes/utils.py +24 -7
- mlrun/serving/v2_serving.py +9 -8
- mlrun/utils/helpers.py +28 -16
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc62.dist-info → mlrun-1.9.0.dist-info}/METADATA +9 -8
- {mlrun-1.8.0rc62.dist-info → mlrun-1.9.0.dist-info}/RECORD +24 -24
- {mlrun-1.8.0rc62.dist-info → mlrun-1.9.0.dist-info}/WHEEL +1 -1
- {mlrun-1.8.0rc62.dist-info → mlrun-1.9.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc62.dist-info → mlrun-1.9.0.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.8.0rc62.dist-info → mlrun-1.9.0.dist-info}/top_level.txt +0 -0
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 -- {
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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'.
|
|
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
|
|
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
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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'.
|
|
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
|
|
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 = [
|
|
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
|
|
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, [
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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, [
|
|
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[
|
|
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
|
-
|
|
446
|
+
mlrun_constants.MLRunInternalLabels.owner: os.environ.get("V3IO_USERNAME")
|
|
447
|
+
or getpass.getuser(),
|
|
440
448
|
# TODO: remove this in 1.10.0
|
|
441
|
-
|
|
449
|
+
mlrun_constants.MLRunInternalLabels.v3io_user: os.environ.get("V3IO_USERNAME"),
|
|
442
450
|
}
|
|
443
|
-
|
|
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
|
|
447
|
-
labels[label
|
|
463
|
+
if label not in labels and enrichment:
|
|
464
|
+
labels[label] = enrichment
|
|
448
465
|
return labels
|
|
449
466
|
|
|
450
467
|
|
mlrun/serving/v2_serving.py
CHANGED
|
@@ -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
|
-
"""
|
|
387
|
+
"""Hook for controlling which results are tracked by the model monitoring
|
|
388
388
|
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
394
|
-
corresponding output values/arrays (the schema of the input/output fields is stored in the model object)
|
|
395
|
-
|
|
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:
|
|
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
|
-
|
|
887
|
-
|
|
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
|
-
|
|
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.
|
|
933
|
-
return "-
|
|
941
|
+
if python_version.startswith("3.9"):
|
|
942
|
+
return "-py39"
|
|
934
943
|
return ""
|
|
935
944
|
|
|
936
|
-
# For mlrun 1.
|
|
937
|
-
# While the python 3.
|
|
938
|
-
# Python 3.
|
|
939
|
-
# and mlrun 1.
|
|
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.
|
|
950
|
+
if semver.VersionInfo.parse("1.11.0-X") > semver.VersionInfo.parse(
|
|
942
951
|
mlrun_version
|
|
943
|
-
) >= semver.VersionInfo.parse("1.
|
|
944
|
-
return "-
|
|
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(
|
|
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
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mlrun
|
|
3
|
-
Version: 1.
|
|
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.
|
|
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.
|
|
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.
|
|
55
|
-
Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.
|
|
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.
|
|
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
|
|
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
|
|
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=
|
|
3
|
-
mlrun/config.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
246
|
-
mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=
|
|
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=
|
|
274
|
+
mlrun/projects/project.py,sha256=VY9Wd1GfMH8CUUdOPN9UDsmcvsddlB_HYd2abodvSXY,237350
|
|
275
275
|
mlrun/runtimes/__init__.py,sha256=J9Sy2HiyMlztNv6VUurMzF5H2XzttNil8nRsWDsqLyg,8923
|
|
276
|
-
mlrun/runtimes/base.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
347
|
-
mlrun-1.
|
|
348
|
-
mlrun-1.
|
|
349
|
-
mlrun-1.
|
|
350
|
-
mlrun-1.
|
|
351
|
-
mlrun-1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|