mlrun 1.6.0rc7__py3-none-any.whl → 1.6.0rc8__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 +27 -27
- mlrun/common/schemas/auth.py +2 -0
- mlrun/config.py +2 -2
- mlrun/datastore/dbfs_store.py +0 -3
- mlrun/datastore/sources.py +12 -2
- mlrun/datastore/targets.py +3 -0
- mlrun/db/httpdb.py +15 -0
- mlrun/feature_store/feature_set.py +5 -2
- mlrun/feature_store/retrieval/spark_merger.py +7 -1
- mlrun/kfpops.py +1 -1
- mlrun/launcher/client.py +1 -6
- mlrun/launcher/remote.py +5 -3
- mlrun/model.py +1 -1
- mlrun/model_monitoring/batch_application.py +48 -85
- mlrun/package/packager.py +115 -89
- mlrun/package/packagers/default_packager.py +66 -65
- mlrun/package/packagers/numpy_packagers.py +109 -62
- mlrun/package/packagers/pandas_packagers.py +12 -23
- mlrun/package/packagers/python_standard_library_packagers.py +35 -57
- mlrun/package/packagers_manager.py +16 -13
- mlrun/package/utils/_pickler.py +8 -18
- mlrun/package/utils/_supported_format.py +1 -1
- mlrun/projects/pipelines.py +11 -6
- mlrun/projects/project.py +11 -4
- mlrun/runtimes/__init__.py +6 -0
- mlrun/runtimes/base.py +8 -0
- mlrun/runtimes/daskjob.py +73 -5
- mlrun/runtimes/local.py +9 -9
- mlrun/runtimes/remotesparkjob.py +1 -0
- mlrun/runtimes/utils.py +1 -1
- mlrun/utils/notifications/notification_pusher.py +1 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.6.0rc7.dist-info → mlrun-1.6.0rc8.dist-info}/METADATA +2 -2
- {mlrun-1.6.0rc7.dist-info → mlrun-1.6.0rc8.dist-info}/RECORD +38 -38
- {mlrun-1.6.0rc7.dist-info → mlrun-1.6.0rc8.dist-info}/WHEEL +1 -1
- {mlrun-1.6.0rc7.dist-info → mlrun-1.6.0rc8.dist-info}/LICENSE +0 -0
- {mlrun-1.6.0rc7.dist-info → mlrun-1.6.0rc8.dist-info}/entry_points.txt +0 -0
- {mlrun-1.6.0rc7.dist-info → mlrun-1.6.0rc8.dist-info}/top_level.txt +0 -0
|
@@ -45,8 +45,7 @@ class NonePackager(DefaultPackager):
|
|
|
45
45
|
DEFAULT_PACKING_ARTIFACT_TYPE = ArtifactType.RESULT
|
|
46
46
|
|
|
47
47
|
# TODO: `None` as pickle will be available from Python 3.10, so this method can be removed once we move to 3.10.
|
|
48
|
-
|
|
49
|
-
def get_supported_artifact_types(cls) -> List[str]:
|
|
48
|
+
def get_supported_artifact_types(self) -> List[str]:
|
|
50
49
|
"""
|
|
51
50
|
Get all the supported artifact types on this packager. It will be the same as `DefaultPackager` but without the
|
|
52
51
|
'object' artifact type support (None cannot be pickled, only from Python 3.10, and it should not be pickled
|
|
@@ -95,9 +94,8 @@ class StrPackager(DefaultPackager):
|
|
|
95
94
|
DEFAULT_PACKING_ARTIFACT_TYPE = ArtifactType.RESULT
|
|
96
95
|
DEFAULT_UNPACKING_ARTIFACT_TYPE = ArtifactType.PATH
|
|
97
96
|
|
|
98
|
-
@classmethod
|
|
99
97
|
def pack_path(
|
|
100
|
-
|
|
98
|
+
self, obj: str, key: str, archive_format: str = DEFAULT_ARCHIVE_FORMAT
|
|
101
99
|
) -> Tuple[Artifact, dict]:
|
|
102
100
|
"""
|
|
103
101
|
Pack a path string value content (pack the file or directory in that path).
|
|
@@ -138,9 +136,11 @@ class StrPackager(DefaultPackager):
|
|
|
138
136
|
|
|
139
137
|
return artifact, instructions
|
|
140
138
|
|
|
141
|
-
@classmethod
|
|
142
139
|
def unpack_path(
|
|
143
|
-
|
|
140
|
+
self,
|
|
141
|
+
data_item: DataItem,
|
|
142
|
+
is_directory: bool = False,
|
|
143
|
+
archive_format: str = None,
|
|
144
144
|
) -> str:
|
|
145
145
|
"""
|
|
146
146
|
Unpack a data item representing a path string. If the path is of a file, the file is downloaded to a local
|
|
@@ -155,11 +155,8 @@ class StrPackager(DefaultPackager):
|
|
|
155
155
|
|
|
156
156
|
:return: The unpacked string.
|
|
157
157
|
"""
|
|
158
|
-
# Get the file
|
|
159
|
-
path =
|
|
160
|
-
|
|
161
|
-
# Mark the downloaded file for future clear:
|
|
162
|
-
cls.add_future_clearing_path(path=path)
|
|
158
|
+
# Get the file:
|
|
159
|
+
path = self.get_data_item_local_path(data_item=data_item)
|
|
163
160
|
|
|
164
161
|
# If it's not a directory, return the file path. Otherwise, it should be extracted according to the archive
|
|
165
162
|
# format:
|
|
@@ -182,7 +179,7 @@ class StrPackager(DefaultPackager):
|
|
|
182
179
|
)
|
|
183
180
|
|
|
184
181
|
# Mark the extracted content for future clear:
|
|
185
|
-
|
|
182
|
+
self.add_future_clearing_path(path=directory_path)
|
|
186
183
|
|
|
187
184
|
# Return the extracted directory path:
|
|
188
185
|
return directory_path
|
|
@@ -196,9 +193,8 @@ class _BuiltinCollectionPackager(DefaultPackager):
|
|
|
196
193
|
DEFAULT_PACKING_ARTIFACT_TYPE = ArtifactType.RESULT
|
|
197
194
|
DEFAULT_UNPACKING_ARTIFACT_TYPE = ArtifactType.FILE
|
|
198
195
|
|
|
199
|
-
@classmethod
|
|
200
196
|
def pack_file(
|
|
201
|
-
|
|
197
|
+
self,
|
|
202
198
|
obj: Union[dict, list],
|
|
203
199
|
key: str,
|
|
204
200
|
file_format: str = DEFAULT_STRUCT_FILE_FORMAT,
|
|
@@ -215,7 +211,7 @@ class _BuiltinCollectionPackager(DefaultPackager):
|
|
|
215
211
|
# Write to file:
|
|
216
212
|
formatter = StructFileSupportedFormat.get_format_handler(fmt=file_format)
|
|
217
213
|
temp_directory = pathlib.Path(tempfile.mkdtemp())
|
|
218
|
-
|
|
214
|
+
self.add_future_clearing_path(path=temp_directory)
|
|
219
215
|
file_path = temp_directory / f"{key}.{file_format}"
|
|
220
216
|
formatter.write(obj=obj, file_path=str(file_path))
|
|
221
217
|
|
|
@@ -225,9 +221,8 @@ class _BuiltinCollectionPackager(DefaultPackager):
|
|
|
225
221
|
|
|
226
222
|
return artifact, instructions
|
|
227
223
|
|
|
228
|
-
@classmethod
|
|
229
224
|
def unpack_file(
|
|
230
|
-
|
|
225
|
+
self, data_item: DataItem, file_format: str = None
|
|
231
226
|
) -> Union[dict, list]:
|
|
232
227
|
"""
|
|
233
228
|
Unpack a builtin collection from file.
|
|
@@ -239,8 +234,7 @@ class _BuiltinCollectionPackager(DefaultPackager):
|
|
|
239
234
|
:return: The unpacked builtin collection.
|
|
240
235
|
"""
|
|
241
236
|
# Get the file:
|
|
242
|
-
file_path =
|
|
243
|
-
cls.add_future_clearing_path(path=file_path)
|
|
237
|
+
file_path = self.get_data_item_local_path(data_item=data_item)
|
|
244
238
|
|
|
245
239
|
# Get the archive format by the file extension if needed:
|
|
246
240
|
if file_format is None:
|
|
@@ -265,8 +259,7 @@ class DictPackager(_BuiltinCollectionPackager):
|
|
|
265
259
|
|
|
266
260
|
PACKABLE_OBJECT_TYPE = dict
|
|
267
261
|
|
|
268
|
-
|
|
269
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> dict:
|
|
262
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> dict:
|
|
270
263
|
"""
|
|
271
264
|
Unpack a dictionary from file.
|
|
272
265
|
|
|
@@ -292,8 +285,7 @@ class ListPackager(_BuiltinCollectionPackager):
|
|
|
292
285
|
|
|
293
286
|
PACKABLE_OBJECT_TYPE = list
|
|
294
287
|
|
|
295
|
-
|
|
296
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> list:
|
|
288
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> list:
|
|
297
289
|
"""
|
|
298
290
|
Unpack a list from file.
|
|
299
291
|
|
|
@@ -338,8 +330,7 @@ class TuplePackager(ListPackager):
|
|
|
338
330
|
|
|
339
331
|
PACKABLE_OBJECT_TYPE = tuple
|
|
340
332
|
|
|
341
|
-
|
|
342
|
-
def pack_result(cls, obj: tuple, key: str) -> dict:
|
|
333
|
+
def pack_result(self, obj: tuple, key: str) -> dict:
|
|
343
334
|
"""
|
|
344
335
|
Pack a tuple as a result.
|
|
345
336
|
|
|
@@ -350,9 +341,8 @@ class TuplePackager(ListPackager):
|
|
|
350
341
|
"""
|
|
351
342
|
return super().pack_result(obj=list(obj), key=key)
|
|
352
343
|
|
|
353
|
-
@classmethod
|
|
354
344
|
def pack_file(
|
|
355
|
-
|
|
345
|
+
self, obj: tuple, key: str, file_format: str = DEFAULT_STRUCT_FILE_FORMAT
|
|
356
346
|
) -> Tuple[Artifact, dict]:
|
|
357
347
|
"""
|
|
358
348
|
Pack a tuple as a file by the given format.
|
|
@@ -365,8 +355,7 @@ class TuplePackager(ListPackager):
|
|
|
365
355
|
"""
|
|
366
356
|
return super().pack_file(obj=list(obj), key=key, file_format=file_format)
|
|
367
357
|
|
|
368
|
-
|
|
369
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> tuple:
|
|
358
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> tuple:
|
|
370
359
|
"""
|
|
371
360
|
Unpack a tuple from file.
|
|
372
361
|
|
|
@@ -386,8 +375,7 @@ class SetPackager(ListPackager):
|
|
|
386
375
|
|
|
387
376
|
PACKABLE_OBJECT_TYPE = set
|
|
388
377
|
|
|
389
|
-
|
|
390
|
-
def pack_result(cls, obj: set, key: str) -> dict:
|
|
378
|
+
def pack_result(self, obj: set, key: str) -> dict:
|
|
391
379
|
"""
|
|
392
380
|
Pack a set as a result.
|
|
393
381
|
|
|
@@ -398,9 +386,8 @@ class SetPackager(ListPackager):
|
|
|
398
386
|
"""
|
|
399
387
|
return super().pack_result(obj=list(obj), key=key)
|
|
400
388
|
|
|
401
|
-
@classmethod
|
|
402
389
|
def pack_file(
|
|
403
|
-
|
|
390
|
+
self, obj: set, key: str, file_format: str = DEFAULT_STRUCT_FILE_FORMAT
|
|
404
391
|
) -> Tuple[Artifact, dict]:
|
|
405
392
|
"""
|
|
406
393
|
Pack a set as a file by the given format.
|
|
@@ -413,8 +400,7 @@ class SetPackager(ListPackager):
|
|
|
413
400
|
"""
|
|
414
401
|
return super().pack_file(obj=list(obj), key=key, file_format=file_format)
|
|
415
402
|
|
|
416
|
-
|
|
417
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> set:
|
|
403
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> set:
|
|
418
404
|
"""
|
|
419
405
|
Unpack a set from file.
|
|
420
406
|
|
|
@@ -434,9 +420,8 @@ class FrozensetPackager(SetPackager):
|
|
|
434
420
|
|
|
435
421
|
PACKABLE_OBJECT_TYPE = frozenset
|
|
436
422
|
|
|
437
|
-
@classmethod
|
|
438
423
|
def pack_file(
|
|
439
|
-
|
|
424
|
+
self, obj: frozenset, key: str, file_format: str = DEFAULT_STRUCT_FILE_FORMAT
|
|
440
425
|
) -> Tuple[Artifact, dict]:
|
|
441
426
|
"""
|
|
442
427
|
Pack a frozenset as a file by the given format.
|
|
@@ -449,8 +434,7 @@ class FrozensetPackager(SetPackager):
|
|
|
449
434
|
"""
|
|
450
435
|
return super().pack_file(obj=set(obj), key=key, file_format=file_format)
|
|
451
436
|
|
|
452
|
-
|
|
453
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> frozenset:
|
|
437
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> frozenset:
|
|
454
438
|
"""
|
|
455
439
|
Unpack a frozenset from file.
|
|
456
440
|
|
|
@@ -472,8 +456,7 @@ class BytesPackager(ListPackager):
|
|
|
472
456
|
|
|
473
457
|
PACKABLE_OBJECT_TYPE = bytes
|
|
474
458
|
|
|
475
|
-
|
|
476
|
-
def pack_result(cls, obj: bytes, key: str) -> dict:
|
|
459
|
+
def pack_result(self, obj: bytes, key: str) -> dict:
|
|
477
460
|
"""
|
|
478
461
|
Pack bytes as a result.
|
|
479
462
|
|
|
@@ -484,9 +467,8 @@ class BytesPackager(ListPackager):
|
|
|
484
467
|
"""
|
|
485
468
|
return {key: obj}
|
|
486
469
|
|
|
487
|
-
@classmethod
|
|
488
470
|
def pack_file(
|
|
489
|
-
|
|
471
|
+
self, obj: bytes, key: str, file_format: str = DEFAULT_STRUCT_FILE_FORMAT
|
|
490
472
|
) -> Tuple[Artifact, dict]:
|
|
491
473
|
"""
|
|
492
474
|
Pack a bytes as a file by the given format.
|
|
@@ -499,8 +481,7 @@ class BytesPackager(ListPackager):
|
|
|
499
481
|
"""
|
|
500
482
|
return super().pack_file(obj=list(obj), key=key, file_format=file_format)
|
|
501
483
|
|
|
502
|
-
|
|
503
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> bytes:
|
|
484
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> bytes:
|
|
504
485
|
"""
|
|
505
486
|
Unpack a bytes from file.
|
|
506
487
|
|
|
@@ -520,8 +501,7 @@ class BytearrayPackager(BytesPackager):
|
|
|
520
501
|
|
|
521
502
|
PACKABLE_OBJECT_TYPE = bytearray
|
|
522
503
|
|
|
523
|
-
|
|
524
|
-
def pack_result(cls, obj: bytearray, key: str) -> dict:
|
|
504
|
+
def pack_result(self, obj: bytearray, key: str) -> dict:
|
|
525
505
|
"""
|
|
526
506
|
Pack a bytearray as a result.
|
|
527
507
|
|
|
@@ -532,9 +512,8 @@ class BytearrayPackager(BytesPackager):
|
|
|
532
512
|
"""
|
|
533
513
|
return {key: bytes(obj)}
|
|
534
514
|
|
|
535
|
-
@classmethod
|
|
536
515
|
def pack_file(
|
|
537
|
-
|
|
516
|
+
self, obj: bytearray, key: str, file_format: str = DEFAULT_STRUCT_FILE_FORMAT
|
|
538
517
|
) -> Tuple[Artifact, dict]:
|
|
539
518
|
"""
|
|
540
519
|
Pack a bytearray as a file by the given format.
|
|
@@ -547,8 +526,7 @@ class BytearrayPackager(BytesPackager):
|
|
|
547
526
|
"""
|
|
548
527
|
return super().pack_file(obj=bytes(obj), key=key, file_format=file_format)
|
|
549
528
|
|
|
550
|
-
|
|
551
|
-
def unpack_file(cls, data_item: DataItem, file_format: str = None) -> bytearray:
|
|
529
|
+
def unpack_file(self, data_item: DataItem, file_format: str = None) -> bytearray:
|
|
552
530
|
"""
|
|
553
531
|
Unpack a bytearray from file.
|
|
554
532
|
|
|
@@ -578,8 +556,7 @@ class PathPackager(StrPackager):
|
|
|
578
556
|
PACK_SUBCLASSES = True
|
|
579
557
|
DEFAULT_PACKING_ARTIFACT_TYPE = "path"
|
|
580
558
|
|
|
581
|
-
|
|
582
|
-
def pack_result(cls, obj: pathlib.Path, key: str) -> dict:
|
|
559
|
+
def pack_result(self, obj: pathlib.Path, key: str) -> dict:
|
|
583
560
|
"""
|
|
584
561
|
Pack the `Path` as a string result.
|
|
585
562
|
|
|
@@ -590,9 +567,8 @@ class PathPackager(StrPackager):
|
|
|
590
567
|
"""
|
|
591
568
|
return super().pack_result(obj=str(obj), key=key)
|
|
592
569
|
|
|
593
|
-
@classmethod
|
|
594
570
|
def pack_path(
|
|
595
|
-
|
|
571
|
+
self, obj: pathlib.Path, key: str, archive_format: str = DEFAULT_ARCHIVE_FORMAT
|
|
596
572
|
) -> Tuple[Artifact, dict]:
|
|
597
573
|
"""
|
|
598
574
|
Pack a `Path` value (pack the file or directory in that path).
|
|
@@ -605,9 +581,11 @@ class PathPackager(StrPackager):
|
|
|
605
581
|
"""
|
|
606
582
|
return super().pack_path(obj=str(obj), key=key, archive_format=archive_format)
|
|
607
583
|
|
|
608
|
-
@classmethod
|
|
609
584
|
def unpack_path(
|
|
610
|
-
|
|
585
|
+
self,
|
|
586
|
+
data_item: DataItem,
|
|
587
|
+
is_directory: bool = False,
|
|
588
|
+
archive_format: str = None,
|
|
611
589
|
) -> pathlib.Path:
|
|
612
590
|
"""
|
|
613
591
|
Unpack a data item representing a `Path`. If the path is of a file, the file is downloaded to a local
|
|
@@ -51,10 +51,10 @@ class PackagersManager:
|
|
|
51
51
|
object or data item. Default to ``mlrun.DefaultPackager``.
|
|
52
52
|
"""
|
|
53
53
|
# Set the default packager:
|
|
54
|
-
self._default_packager = default_packager or DefaultPackager
|
|
54
|
+
self._default_packager = (default_packager or DefaultPackager)()
|
|
55
55
|
|
|
56
56
|
# Initialize the packagers list (with the default packager in it):
|
|
57
|
-
self._packagers: List[
|
|
57
|
+
self._packagers: List[Packager] = []
|
|
58
58
|
|
|
59
59
|
# Set an artifacts list and results dictionary to collect all packed objects (will be used later to write extra
|
|
60
60
|
# data if noted by the user using the log hint key "extra_data")
|
|
@@ -80,7 +80,7 @@ class PackagersManager:
|
|
|
80
80
|
return self._results
|
|
81
81
|
|
|
82
82
|
def collect_packagers(
|
|
83
|
-
self, packagers: List[Union[Type, str]], default_priority: int = 5
|
|
83
|
+
self, packagers: List[Union[Type[Packager], str]], default_priority: int = 5
|
|
84
84
|
):
|
|
85
85
|
"""
|
|
86
86
|
Collect the provided packagers. Packagers passed as module paths are imported and validated to be of type
|
|
@@ -155,9 +155,11 @@ class PackagersManager:
|
|
|
155
155
|
raise MLRunPackageCollectionError(
|
|
156
156
|
f"The packager '{packager.__name__}' could not be collected as it is not a `mlrun.Packager`."
|
|
157
157
|
)
|
|
158
|
+
# Initialize the packager class:
|
|
159
|
+
packager = packager()
|
|
158
160
|
# Set default priority in case it is not set in the packager's class:
|
|
159
|
-
if packager.
|
|
160
|
-
packager.
|
|
161
|
+
if packager.priority is ...:
|
|
162
|
+
packager.priority = default_priority
|
|
161
163
|
# Collect the packager (putting him first in the list for highest priority:
|
|
162
164
|
self._packagers.insert(0, packager)
|
|
163
165
|
# For debugging, we'll print the collected packager:
|
|
@@ -350,13 +352,14 @@ class PackagersManager:
|
|
|
350
352
|
artifacts, to ensure that files that require uploading have already been uploaded.
|
|
351
353
|
"""
|
|
352
354
|
for packager in self._get_packagers_with_default_packager():
|
|
353
|
-
for path in packager.
|
|
355
|
+
for path in packager.future_clearing_path_list:
|
|
354
356
|
if not os.path.exists(path):
|
|
355
357
|
continue
|
|
356
358
|
if os.path.isdir(path):
|
|
357
359
|
shutil.rmtree(path)
|
|
358
360
|
else:
|
|
359
361
|
os.remove(path)
|
|
362
|
+
packager.future_clearing_path_list.clear()
|
|
360
363
|
|
|
361
364
|
class _InstructionsNotesKey:
|
|
362
365
|
"""
|
|
@@ -368,7 +371,7 @@ class PackagersManager:
|
|
|
368
371
|
ARTIFACT_TYPE = "artifact_type"
|
|
369
372
|
INSTRUCTIONS = "instructions"
|
|
370
373
|
|
|
371
|
-
def _get_packagers_with_default_packager(self) -> List[
|
|
374
|
+
def _get_packagers_with_default_packager(self) -> List[Packager]:
|
|
372
375
|
"""
|
|
373
376
|
Get the full list of packagers - the collected packagers and the default packager (located at last place in the
|
|
374
377
|
list - the lowest priority).
|
|
@@ -377,7 +380,7 @@ class PackagersManager:
|
|
|
377
380
|
"""
|
|
378
381
|
return [*self._packagers, self._default_packager]
|
|
379
382
|
|
|
380
|
-
def _get_packager_by_name(self, name: str) -> Union[
|
|
383
|
+
def _get_packager_by_name(self, name: str) -> Union[Packager, None]:
|
|
381
384
|
"""
|
|
382
385
|
Look for a packager with the given name and return it.
|
|
383
386
|
|
|
@@ -389,7 +392,7 @@ class PackagersManager:
|
|
|
389
392
|
"""
|
|
390
393
|
# Look for a packager by exact name:
|
|
391
394
|
for packager in self._get_packagers_with_default_packager():
|
|
392
|
-
if packager.__name__ == name:
|
|
395
|
+
if packager.__class__.__name__ == name:
|
|
393
396
|
return packager
|
|
394
397
|
|
|
395
398
|
# No packager was found:
|
|
@@ -401,7 +404,7 @@ class PackagersManager:
|
|
|
401
404
|
obj: Any,
|
|
402
405
|
artifact_type: str = None,
|
|
403
406
|
configurations: dict = None,
|
|
404
|
-
) -> Union[
|
|
407
|
+
) -> Union[Packager, None]:
|
|
405
408
|
"""
|
|
406
409
|
Look for a packager that can pack the provided object as the provided artifact type.
|
|
407
410
|
|
|
@@ -428,7 +431,7 @@ class PackagersManager:
|
|
|
428
431
|
data_item: Any,
|
|
429
432
|
type_hint: type,
|
|
430
433
|
artifact_type: str = None,
|
|
431
|
-
) -> Union[
|
|
434
|
+
) -> Union[Packager, None]:
|
|
432
435
|
"""
|
|
433
436
|
Look for a packager that can unpack the data item of the given type hint as the provided artifact type.
|
|
434
437
|
|
|
@@ -495,7 +498,7 @@ class PackagersManager:
|
|
|
495
498
|
|
|
496
499
|
# Prepare the manager's unpackaging instructions:
|
|
497
500
|
unpackaging_instructions = {
|
|
498
|
-
self._InstructionsNotesKey.PACKAGER_NAME: packager.__name__,
|
|
501
|
+
self._InstructionsNotesKey.PACKAGER_NAME: packager.__class__.__name__,
|
|
499
502
|
self._InstructionsNotesKey.OBJECT_TYPE: self._get_type_name(typ=type(obj)),
|
|
500
503
|
self._InstructionsNotesKey.ARTIFACT_TYPE: (
|
|
501
504
|
artifact_type
|
|
@@ -646,7 +649,7 @@ class PackagersManager:
|
|
|
646
649
|
:raise MLRunPackageUnpackingError: If there is no packager that supports the provided type hint.
|
|
647
650
|
"""
|
|
648
651
|
# Prepare a list of a packager and exception string for all the failures in case there was no fitting packager:
|
|
649
|
-
found_packagers: List[Tuple[
|
|
652
|
+
found_packagers: List[Tuple[Packager, str]] = []
|
|
650
653
|
|
|
651
654
|
# Try to unpack as one of the possible types in the type hint:
|
|
652
655
|
possible_type_hints = {type_hint}
|
mlrun/package/utils/_pickler.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
import importlib
|
|
16
|
+
import importlib.metadata as importlib_metadata
|
|
16
17
|
import os
|
|
17
18
|
import sys
|
|
18
19
|
import tempfile
|
|
@@ -188,26 +189,15 @@ class Pickler:
|
|
|
188
189
|
"""
|
|
189
190
|
# First we'll try to get the module version from `importlib`:
|
|
190
191
|
try:
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
): # TODO: Remove once Python 3.7 is not supported.
|
|
196
|
-
from importlib.metadata import version
|
|
197
|
-
else:
|
|
198
|
-
from importlib_metadata import version
|
|
199
|
-
|
|
200
|
-
return version(module_name)
|
|
201
|
-
except (ModuleNotFoundError, importlib.metadata.PackageNotFoundError):
|
|
202
|
-
# User won't necessarily have the `importlib_metadata` module, so we will ignore it by catching
|
|
203
|
-
# `ModuleNotFoundError`. `PackageNotFoundError` is ignored as well as this is raised when `version` could
|
|
204
|
-
# not find the package related to the module.
|
|
192
|
+
return importlib_metadata.version(module_name)
|
|
193
|
+
except importlib.metadata.PackageNotFoundError:
|
|
194
|
+
# `PackageNotFoundError` is ignored this is raised when `version` could not find the package related to the
|
|
195
|
+
# module.
|
|
205
196
|
pass
|
|
206
197
|
|
|
207
|
-
# Secondly, if importlib could not get the version
|
|
208
|
-
#
|
|
209
|
-
#
|
|
210
|
-
# 'pip install x'):
|
|
198
|
+
# Secondly, if importlib could not get the version, we'll try to use `pkg_resources` to get the version (the
|
|
199
|
+
# version will be found only if the package name is equal to the module name. For example, if the module name is
|
|
200
|
+
# 'x' then the way we installed the package must be 'pip install x'):
|
|
211
201
|
import pkg_resources
|
|
212
202
|
|
|
213
203
|
with warnings.catch_warnings():
|
|
@@ -24,7 +24,7 @@ class SupportedFormat(ABC, Generic[FileHandlerType]):
|
|
|
24
24
|
Library of supported formats by some builtin MLRun packagers.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
# Add here
|
|
27
|
+
# Add here all the supported formats in ALL CAPS and their value as a string:
|
|
28
28
|
...
|
|
29
29
|
|
|
30
30
|
# The map to use in the method `get_format_handler`. A dictionary of string key to a class type to handle that
|
mlrun/projects/pipelines.py
CHANGED
|
@@ -133,7 +133,7 @@ class WorkflowSpec(mlrun.model.ModelObj):
|
|
|
133
133
|
required.remove(k)
|
|
134
134
|
if required:
|
|
135
135
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
136
|
-
f"
|
|
136
|
+
f"Workflow argument(s) {','.join(required)} are required and were not specified"
|
|
137
137
|
)
|
|
138
138
|
|
|
139
139
|
def clear_tmp(self):
|
|
@@ -246,7 +246,7 @@ class _PipelineContext:
|
|
|
246
246
|
return True
|
|
247
247
|
if raise_exception:
|
|
248
248
|
raise ValueError(
|
|
249
|
-
"
|
|
249
|
+
"Pipeline context is not initialized, must be used inside a pipeline"
|
|
250
250
|
)
|
|
251
251
|
return False
|
|
252
252
|
|
|
@@ -670,7 +670,7 @@ class _KFPRunner(_PipelineRunner):
|
|
|
670
670
|
raise_error = None
|
|
671
671
|
try:
|
|
672
672
|
if timeout:
|
|
673
|
-
logger.info("
|
|
673
|
+
logger.info("Waiting for pipeline run completion")
|
|
674
674
|
state = run.wait_for_completion(
|
|
675
675
|
timeout=timeout, expected_statuses=expected_statuses
|
|
676
676
|
)
|
|
@@ -681,6 +681,7 @@ class _KFPRunner(_PipelineRunner):
|
|
|
681
681
|
mldb = mlrun.db.get_run_db(secrets=project._secrets)
|
|
682
682
|
runs = mldb.list_runs(project=project.name, labels=f"workflow={run.run_id}")
|
|
683
683
|
|
|
684
|
+
# TODO: The below section duplicates notifiers.push_pipeline_run_results() logic. We should use it instead.
|
|
684
685
|
had_errors = 0
|
|
685
686
|
for r in runs:
|
|
686
687
|
if r["status"].get("state", "") == "error":
|
|
@@ -909,7 +910,7 @@ class _RemoteRunner(_PipelineRunner):
|
|
|
909
910
|
):
|
|
910
911
|
# ignore notifiers, as they are handled by the remote pipeline notifications,
|
|
911
912
|
# so overriding with CustomNotificationPusher with empty list of notifiers
|
|
912
|
-
|
|
913
|
+
state, had_errors, text = _KFPRunner.get_run_status(
|
|
913
914
|
project,
|
|
914
915
|
run,
|
|
915
916
|
timeout,
|
|
@@ -917,11 +918,15 @@ class _RemoteRunner(_PipelineRunner):
|
|
|
917
918
|
notifiers=mlrun.utils.notifications.CustomNotificationPusher([]),
|
|
918
919
|
)
|
|
919
920
|
|
|
921
|
+
# indicate the pipeline status since we don't push the notifications in the remote runner
|
|
922
|
+
logger.info(text)
|
|
923
|
+
return state, had_errors, text
|
|
924
|
+
|
|
920
925
|
|
|
921
926
|
def create_pipeline(project, pipeline, functions, secrets=None, handler=None):
|
|
922
927
|
spec = imputil.spec_from_file_location("workflow", pipeline)
|
|
923
928
|
if spec is None:
|
|
924
|
-
raise ImportError(f"
|
|
929
|
+
raise ImportError(f"Cannot import workflow {pipeline}")
|
|
925
930
|
mod = imputil.module_from_spec(spec)
|
|
926
931
|
spec.loader.exec_module(mod)
|
|
927
932
|
|
|
@@ -1076,7 +1081,7 @@ def load_and_run(
|
|
|
1076
1081
|
raise RuntimeError(f"Workflow {workflow_log_message} failed") from run.exc
|
|
1077
1082
|
|
|
1078
1083
|
if wait_for_completion:
|
|
1079
|
-
pipeline_state =
|
|
1084
|
+
pipeline_state, _, _ = project.get_run_status(run)
|
|
1080
1085
|
context.log_result(key="workflow_state", value=pipeline_state, commit=True)
|
|
1081
1086
|
if pipeline_state != mlrun.run.RunStatuses.succeeded:
|
|
1082
1087
|
raise RuntimeError(
|
mlrun/projects/project.py
CHANGED
|
@@ -103,9 +103,9 @@ def init_repo(context, url, init_git):
|
|
|
103
103
|
repo = None
|
|
104
104
|
context_path = pathlib.Path(context)
|
|
105
105
|
if not context_path.exists():
|
|
106
|
-
context_path.mkdir(parents=True)
|
|
106
|
+
context_path.mkdir(parents=True, exist_ok=True)
|
|
107
107
|
elif not context_path.is_dir():
|
|
108
|
-
raise ValueError(f"
|
|
108
|
+
raise ValueError(f"Context {context} is not a dir path")
|
|
109
109
|
try:
|
|
110
110
|
repo = git.Repo(context)
|
|
111
111
|
url = get_repo_url(repo)
|
|
@@ -222,6 +222,7 @@ def new_project(
|
|
|
222
222
|
if remote and url != remote:
|
|
223
223
|
project.create_remote(remote)
|
|
224
224
|
elif url:
|
|
225
|
+
logger.info("Identified pre-initialized git repo, using it", url=url)
|
|
225
226
|
project.spec._source = url
|
|
226
227
|
project.spec.origin_url = url
|
|
227
228
|
if description:
|
|
@@ -367,7 +368,7 @@ def load_project(
|
|
|
367
368
|
project = _load_project_dir(context, name, subpath)
|
|
368
369
|
|
|
369
370
|
if not project.metadata.name:
|
|
370
|
-
raise ValueError("
|
|
371
|
+
raise ValueError("Project name must be specified")
|
|
371
372
|
|
|
372
373
|
if parameters:
|
|
373
374
|
# Enable setting project parameters at load time, can be used to customize the project_setup
|
|
@@ -3479,7 +3480,13 @@ def _init_function_from_dict(
|
|
|
3479
3480
|
)
|
|
3480
3481
|
|
|
3481
3482
|
elif url.endswith(".py"):
|
|
3482
|
-
|
|
3483
|
+
# when load_source_on_run is used we allow not providing image as code will be loaded pre-run. ML-4994
|
|
3484
|
+
if (
|
|
3485
|
+
not image
|
|
3486
|
+
and not project.default_image
|
|
3487
|
+
and kind != "local"
|
|
3488
|
+
and not project.spec.load_source_on_run
|
|
3489
|
+
):
|
|
3483
3490
|
raise ValueError(
|
|
3484
3491
|
"image must be provided with py code files which do not "
|
|
3485
3492
|
"run on 'local' engine kind"
|
mlrun/runtimes/__init__.py
CHANGED
|
@@ -199,6 +199,12 @@ class RuntimeKinds(object):
|
|
|
199
199
|
return True
|
|
200
200
|
return False
|
|
201
201
|
|
|
202
|
+
@staticmethod
|
|
203
|
+
def requires_image_name_for_execution(kind):
|
|
204
|
+
if RuntimeKinds.is_local_runtime(kind):
|
|
205
|
+
return False
|
|
206
|
+
return kind not in [RuntimeKinds.spark]
|
|
207
|
+
|
|
202
208
|
|
|
203
209
|
def get_runtime_class(kind: str):
|
|
204
210
|
if kind == RuntimeKinds.mpijob:
|
mlrun/runtimes/base.py
CHANGED
|
@@ -800,6 +800,14 @@ class BaseRuntime(ModelObj):
|
|
|
800
800
|
self.spec.build = {}
|
|
801
801
|
return self
|
|
802
802
|
|
|
803
|
+
def requires_build(self) -> bool:
|
|
804
|
+
build = self.spec.build
|
|
805
|
+
return (
|
|
806
|
+
build.commands
|
|
807
|
+
or build.requirements
|
|
808
|
+
or (build.source and not build.load_source_on_run)
|
|
809
|
+
)
|
|
810
|
+
|
|
803
811
|
def prepare_image_for_deploy(self):
|
|
804
812
|
"""
|
|
805
813
|
if a function has a 'spec.image' it is considered to be deployed,
|