mlrun 1.3.1rc5__py3-none-any.whl → 1.4.0rc2__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (67) hide show
  1. mlrun/__main__.py +57 -4
  2. mlrun/api/api/endpoints/marketplace.py +57 -4
  3. mlrun/api/api/endpoints/runs.py +2 -0
  4. mlrun/api/api/utils.py +102 -0
  5. mlrun/api/crud/__init__.py +1 -0
  6. mlrun/api/crud/marketplace.py +133 -44
  7. mlrun/api/crud/notifications.py +80 -0
  8. mlrun/api/crud/runs.py +2 -0
  9. mlrun/api/crud/secrets.py +1 -0
  10. mlrun/api/db/base.py +32 -0
  11. mlrun/api/db/session.py +3 -11
  12. mlrun/api/db/sqldb/db.py +162 -1
  13. mlrun/api/db/sqldb/models/models_mysql.py +41 -0
  14. mlrun/api/db/sqldb/models/models_sqlite.py +35 -0
  15. mlrun/api/main.py +54 -1
  16. mlrun/api/migrations_mysql/versions/c905d15bd91d_notifications.py +70 -0
  17. mlrun/api/migrations_sqlite/versions/959ae00528ad_notifications.py +61 -0
  18. mlrun/api/schemas/__init__.py +1 -0
  19. mlrun/api/schemas/marketplace.py +18 -8
  20. mlrun/api/{db/filedb/__init__.py → schemas/notification.py} +17 -1
  21. mlrun/api/utils/singletons/db.py +8 -14
  22. mlrun/builder.py +37 -26
  23. mlrun/config.py +12 -2
  24. mlrun/data_types/spark.py +9 -2
  25. mlrun/datastore/base.py +10 -1
  26. mlrun/datastore/sources.py +1 -1
  27. mlrun/db/__init__.py +6 -4
  28. mlrun/db/base.py +1 -2
  29. mlrun/db/httpdb.py +32 -6
  30. mlrun/db/nopdb.py +463 -0
  31. mlrun/db/sqldb.py +47 -7
  32. mlrun/execution.py +3 -0
  33. mlrun/feature_store/api.py +26 -12
  34. mlrun/feature_store/common.py +1 -1
  35. mlrun/feature_store/steps.py +110 -13
  36. mlrun/k8s_utils.py +10 -0
  37. mlrun/model.py +43 -0
  38. mlrun/projects/operations.py +5 -2
  39. mlrun/projects/pipelines.py +4 -3
  40. mlrun/projects/project.py +50 -10
  41. mlrun/run.py +5 -4
  42. mlrun/runtimes/__init__.py +2 -6
  43. mlrun/runtimes/base.py +82 -31
  44. mlrun/runtimes/function.py +22 -0
  45. mlrun/runtimes/kubejob.py +10 -8
  46. mlrun/runtimes/serving.py +1 -1
  47. mlrun/runtimes/sparkjob/__init__.py +0 -1
  48. mlrun/runtimes/sparkjob/abstract.py +0 -2
  49. mlrun/serving/states.py +2 -2
  50. mlrun/utils/helpers.py +1 -1
  51. mlrun/utils/notifications/notification/__init__.py +1 -1
  52. mlrun/utils/notifications/notification/base.py +14 -13
  53. mlrun/utils/notifications/notification/console.py +6 -3
  54. mlrun/utils/notifications/notification/git.py +19 -12
  55. mlrun/utils/notifications/notification/ipython.py +6 -3
  56. mlrun/utils/notifications/notification/slack.py +13 -12
  57. mlrun/utils/notifications/notification_pusher.py +185 -37
  58. mlrun/utils/version/version.json +2 -2
  59. {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/METADATA +6 -2
  60. {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/RECORD +64 -63
  61. mlrun/api/db/filedb/db.py +0 -518
  62. mlrun/db/filedb.py +0 -899
  63. mlrun/runtimes/sparkjob/spark2job.py +0 -59
  64. {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/LICENSE +0 -0
  65. {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/WHEEL +0 -0
  66. {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/entry_points.txt +0 -0
  67. {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/top_level.txt +0 -0
mlrun/db/filedb.py DELETED
@@ -1,899 +0,0 @@
1
- # Copyright 2018 Iguazio
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- import json
16
- import pathlib
17
- import typing
18
- from datetime import datetime, timedelta, timezone
19
- from os import listdir, makedirs, path, remove, scandir
20
- from typing import List, Optional, Union
21
-
22
- import yaml
23
- from dateutil.parser import parse as parse_time
24
-
25
- import mlrun.api.schemas
26
- import mlrun.errors
27
- import mlrun.model_monitoring.model_endpoint
28
-
29
- from ..api import schemas
30
- from ..config import config
31
- from ..datastore import store_manager
32
- from ..lists import ArtifactList, RunList
33
- from ..utils import (
34
- dict_to_json,
35
- dict_to_yaml,
36
- fill_function_hash,
37
- generate_object_uri,
38
- get_in,
39
- logger,
40
- match_labels,
41
- match_times,
42
- match_value,
43
- match_value_options,
44
- update_in,
45
- )
46
- from .base import RunDBError, RunDBInterface
47
-
48
- run_logs = "runs"
49
- artifacts_dir = "artifacts"
50
- functions_dir = "functions"
51
- schedules_dir = "schedules"
52
-
53
-
54
- # TODO: remove fileDB, doesn't needs to be used anymore
55
- class FileRunDB(RunDBInterface):
56
- kind = "file"
57
-
58
- def __init__(self, dirpath="", format=".yaml"):
59
- self.format = format
60
- self.dirpath = dirpath
61
- self._datastore = None
62
- self._subpath = None
63
- self._secrets: typing.Optional[mlrun.secrets.SecretsStore] = None
64
- self._projects = {}
65
- makedirs(self.schedules_dir, exist_ok=True)
66
-
67
- def connect(self, secrets=None):
68
- self._secrets = secrets
69
- return self
70
-
71
- def _connect(self, secrets=None):
72
- sm = store_manager.set(secrets or self._secrets)
73
- self._datastore, self._subpath = sm.get_or_create_store(self.dirpath)
74
- return self
75
-
76
- @property
77
- def datastore(self):
78
- if not self._datastore:
79
- self._connect()
80
- return self._datastore
81
-
82
- def store_log(self, uid, project="", body=None, append=False):
83
- filepath = self._filepath(run_logs, project, uid, "") + ".log"
84
- makedirs(path.dirname(filepath), exist_ok=True)
85
- mode = "ab" if append else "wb"
86
- with open(filepath, mode) as fp:
87
- fp.write(body)
88
- fp.close()
89
-
90
- def get_log(self, uid, project="", offset=0, size=0):
91
- filepath = self._filepath(run_logs, project, uid, "") + ".log"
92
- if pathlib.Path(filepath).is_file():
93
- with open(filepath, "rb") as fp:
94
- if offset:
95
- fp.seek(offset)
96
- if not size:
97
- size = 2**18
98
- return "", fp.read(size)
99
- return "", None
100
-
101
- def _run_path(self, uid, iter):
102
- if iter:
103
- return f"{uid}-{iter}"
104
- return uid
105
-
106
- def store_run(self, struct, uid, project="", iter=0):
107
- data = self._dumps(struct)
108
- filepath = (
109
- self._filepath(run_logs, project, self._run_path(uid, iter), "")
110
- + self.format
111
- )
112
- self.datastore.put(filepath, data)
113
-
114
- def update_run(self, updates: dict, uid, project="", iter=0):
115
- run = self.read_run(uid, project, iter=iter)
116
- if run and updates:
117
- for key, val in updates.items():
118
- update_in(run, key, val)
119
- self.store_run(run, uid, project, iter=iter)
120
-
121
- def abort_run(self, uid, project="", iter=0):
122
- raise NotImplementedError()
123
-
124
- def read_run(self, uid, project="", iter=0):
125
- filepath = (
126
- self._filepath(run_logs, project, self._run_path(uid, iter), "")
127
- + self.format
128
- )
129
- if not pathlib.Path(filepath).is_file():
130
- raise mlrun.errors.MLRunNotFoundError(uid)
131
- data = self.datastore.get(filepath)
132
- return self._loads(data)
133
-
134
- def list_runs(
135
- self,
136
- name="",
137
- uid: Optional[Union[str, List[str]]] = None,
138
- project="",
139
- labels=None,
140
- state="",
141
- sort=True,
142
- last=1000,
143
- iter=False,
144
- start_time_from: datetime = None,
145
- start_time_to: datetime = None,
146
- last_update_time_from: datetime = None,
147
- last_update_time_to: datetime = None,
148
- partition_by: Union[schemas.RunPartitionByField, str] = None,
149
- rows_per_partition: int = 1,
150
- partition_sort_by: Union[schemas.SortField, str] = None,
151
- partition_order: Union[schemas.OrderType, str] = schemas.OrderType.desc,
152
- max_partitions: int = 0,
153
- ):
154
- if partition_by is not None:
155
- raise mlrun.errors.MLRunInvalidArgumentError(
156
- "Runs partitioning not supported"
157
- )
158
- if uid and isinstance(uid, list):
159
- raise mlrun.errors.MLRunInvalidArgumentError(
160
- "Runs list with multiple uids not supported"
161
- )
162
-
163
- labels = [] if labels is None else labels
164
- filepath = self._filepath(run_logs, project)
165
- results = RunList()
166
- if isinstance(labels, str):
167
- labels = labels.split(",")
168
- for run, _ in self._load_list(filepath, "*"):
169
- if (
170
- match_value(name, run, "metadata.name")
171
- and match_labels(get_in(run, "metadata.labels", {}), labels)
172
- and match_value_options(state, run, "status.state")
173
- and match_value(uid, run, "metadata.uid")
174
- and match_times(
175
- start_time_from,
176
- start_time_to,
177
- run,
178
- "status.start_time",
179
- )
180
- and match_times(
181
- last_update_time_from,
182
- last_update_time_to,
183
- run,
184
- "status.last_update",
185
- )
186
- and (iter or get_in(run, "metadata.iteration", 0) == 0)
187
- ):
188
- results.append(run)
189
-
190
- if sort or last:
191
- results.sort(
192
- key=lambda i: get_in(i, ["status", "start_time"], ""), reverse=True
193
- )
194
- if last and len(results) > last:
195
- return RunList(results[:last])
196
- return results
197
-
198
- def del_run(self, uid, project="", iter=0):
199
- filepath = (
200
- self._filepath(run_logs, project, self._run_path(uid, iter), "")
201
- + self.format
202
- )
203
- self._safe_del(filepath)
204
-
205
- def del_runs(self, name="", project="", labels=None, state="", days_ago=0):
206
-
207
- labels = [] if labels is None else labels
208
- if not any([name, state, days_ago, labels]):
209
- raise RunDBError(
210
- "filter is too wide, select name and/or state and/or days_ago"
211
- )
212
-
213
- filepath = self._filepath(run_logs, project)
214
- if isinstance(labels, str):
215
- labels = labels.split(",")
216
-
217
- if days_ago:
218
- days_ago = datetime.now() - timedelta(days=days_ago)
219
-
220
- def date_before(run):
221
- d = get_in(run, "status.start_time", "")
222
- if not d:
223
- return False
224
- return parse_time(d) < days_ago
225
-
226
- for run, p in self._load_list(filepath, "*"):
227
- if (
228
- match_value(name, run, "metadata.name")
229
- and match_labels(get_in(run, "metadata.labels", {}), labels)
230
- and match_value(state, run, "status.state")
231
- and (not days_ago or date_before(run))
232
- ):
233
- self._safe_del(p)
234
-
235
- def store_artifact(self, key, artifact, uid, iter=None, tag="", project=""):
236
- if "updated" not in artifact:
237
- artifact["updated"] = datetime.now(timezone.utc).isoformat()
238
- data = self._dumps(artifact)
239
- if iter:
240
- key = f"{iter}-{key}"
241
- filepath = self._filepath(artifacts_dir, project, key, uid) + self.format
242
- self.datastore.put(filepath, data)
243
- filepath = (
244
- self._filepath(artifacts_dir, project, key, tag or "latest") + self.format
245
- )
246
- self.datastore.put(filepath, data)
247
-
248
- def read_artifact(self, key, tag="", iter=None, project=""):
249
- tag = tag or "latest"
250
- if iter:
251
- key = f"{iter}-{key}"
252
- filepath = self._filepath(artifacts_dir, project, key, tag) + self.format
253
-
254
- if not pathlib.Path(filepath).is_file():
255
- raise RunDBError(key)
256
- data = self.datastore.get(filepath)
257
- return self._loads(data)
258
-
259
- def list_artifacts(
260
- self,
261
- name="",
262
- project="",
263
- tag="",
264
- labels=None,
265
- since=None,
266
- until=None,
267
- iter: int = None,
268
- best_iteration: bool = False,
269
- kind: str = None,
270
- category: Union[str, schemas.ArtifactCategories] = None,
271
- ):
272
- if iter or kind or category:
273
- raise NotImplementedError(
274
- "iter/kind/category parameters are not supported for filedb implementation"
275
- )
276
-
277
- labels = [] if labels is None else labels
278
- tag = tag or "latest"
279
- name = name or ""
280
- logger.info(f"reading artifacts in {project} name/mask: {name} tag: {tag} ...")
281
- filepath = self._filepath(artifacts_dir, project, tag=tag)
282
- results = ArtifactList()
283
- results.tag = tag
284
- if isinstance(labels, str):
285
- labels = labels.split(",")
286
- if tag == "*":
287
- mask = "**/*" + name
288
- if name:
289
- mask += "*"
290
- else:
291
- mask = "**/*"
292
-
293
- time_pred = make_time_pred(since, until)
294
- for artifact, p in self._load_list(filepath, mask):
295
- if (name == "" or name in get_in(artifact, "key", "")) and match_labels(
296
- get_in(artifact, "labels", {}), labels
297
- ):
298
- if not time_pred(artifact):
299
- continue
300
- if "artifacts/latest" in p:
301
- artifact["tree"] = "latest"
302
- results.append(artifact)
303
-
304
- return results
305
-
306
- def del_artifact(self, key, tag="", project=""):
307
- tag = tag or "latest"
308
- filepath = self._filepath(artifacts_dir, project, key, tag) + self.format
309
- self._safe_del(filepath)
310
-
311
- def del_artifacts(self, name="", project="", tag="", labels=None):
312
- labels = [] if labels is None else labels
313
- tag = tag or "latest"
314
- filepath = self._filepath(artifacts_dir, project, tag=tag)
315
-
316
- if isinstance(labels, str):
317
- labels = labels.split(",")
318
- if tag == "*":
319
- mask = "**/*" + name
320
- if name:
321
- mask += "*"
322
- else:
323
- mask = "**/*"
324
-
325
- for artifact, p in self._load_list(filepath, mask):
326
- if (name == "" or name == get_in(artifact, "key", "")) and match_labels(
327
- get_in(artifact, "labels", {}), labels
328
- ):
329
-
330
- self._safe_del(p)
331
-
332
- def store_function(self, function, name, project="", tag="", versioned=False):
333
- tag = tag or get_in(function, "metadata.tag") or "latest"
334
- hash_key = fill_function_hash(function, tag)
335
- update_in(function, "metadata.updated", datetime.now(timezone.utc))
336
- update_in(function, "metadata.tag", "")
337
- data = self._dumps(function)
338
- filepath = (
339
- path.join(
340
- self.dirpath,
341
- functions_dir,
342
- project or config.default_project,
343
- name,
344
- tag,
345
- )
346
- + self.format
347
- )
348
- self.datastore.put(filepath, data)
349
- if versioned:
350
-
351
- # the "hash_key" version should not include the status
352
- function["status"] = None
353
-
354
- # versioned means we want this function to be queryable by its hash key so save another file that the
355
- # hash key is the file name
356
- filepath = (
357
- path.join(
358
- self.dirpath,
359
- functions_dir,
360
- project or config.default_project,
361
- name,
362
- hash_key,
363
- )
364
- + self.format
365
- )
366
- data = self._dumps(function)
367
- self.datastore.put(filepath, data)
368
- return hash_key
369
-
370
- def get_function(self, name, project="", tag="", hash_key=""):
371
- tag = tag or "latest"
372
- file_name = hash_key or tag
373
- filepath = (
374
- path.join(
375
- self.dirpath,
376
- functions_dir,
377
- project or config.default_project,
378
- name,
379
- file_name,
380
- )
381
- + self.format
382
- )
383
- if not pathlib.Path(filepath).is_file():
384
- function_uri = generate_object_uri(project, name, tag, hash_key)
385
- raise mlrun.errors.MLRunNotFoundError(f"Function not found {function_uri}")
386
- data = self.datastore.get(filepath)
387
- parsed_data = self._loads(data)
388
-
389
- # tag should be filled only when queried by tag
390
- parsed_data["metadata"]["tag"] = "" if hash_key else tag
391
- return parsed_data
392
-
393
- def delete_function(self, name: str, project: str = ""):
394
- raise NotImplementedError()
395
-
396
- def list_functions(self, name=None, project="", tag="", labels=None):
397
- labels = labels or []
398
- logger.info(f"reading functions in {project} name/mask: {name} tag: {tag} ...")
399
- filepath = path.join(
400
- self.dirpath,
401
- functions_dir,
402
- project or config.default_project,
403
- )
404
- filepath += "/"
405
-
406
- # function name -> tag name -> function dict
407
- functions_with_tag_filename = {}
408
- # function name -> hash key -> function dict
409
- functions_with_hash_key_filename = {}
410
- # function name -> hash keys set
411
- function_with_tag_hash_keys = {}
412
- if isinstance(labels, str):
413
- labels = labels.split(",")
414
- mask = "**/*"
415
- if name:
416
- filepath = f"{filepath}{name}/"
417
- mask = "*"
418
- for func, fullname in self._load_list(filepath, mask):
419
- if match_labels(get_in(func, "metadata.labels", {}), labels):
420
- file_name, _ = path.splitext(path.basename(fullname))
421
- function_name = path.basename(path.dirname(fullname))
422
- target_dict = functions_with_tag_filename
423
-
424
- tag_name = file_name
425
- # Heuristic - if tag length is bigger than 20 it's probably a hash key
426
- if len(tag_name) > 20: # hash vs tags
427
- tag_name = ""
428
- target_dict = functions_with_hash_key_filename
429
- else:
430
- function_with_tag_hash_keys.setdefault(function_name, set()).add(
431
- func["metadata"]["hash"]
432
- )
433
- update_in(func, "metadata.tag", tag_name)
434
- target_dict.setdefault(function_name, {})[file_name] = func
435
-
436
- # clean duplicated function e.g. function that was saved both in a hash key filename and tag filename
437
- for (
438
- function_name,
439
- hash_keys_to_function_dict_map,
440
- ) in functions_with_hash_key_filename.items():
441
- function_hash_keys_to_remove = []
442
- for (
443
- function_hash_key,
444
- function_dict,
445
- ) in hash_keys_to_function_dict_map.items():
446
- if function_hash_key in function_with_tag_hash_keys.get(
447
- function_name, set()
448
- ):
449
- function_hash_keys_to_remove.append(function_hash_key)
450
-
451
- for function_hash_key in function_hash_keys_to_remove:
452
- del hash_keys_to_function_dict_map[function_hash_key]
453
-
454
- results = []
455
- for functions_map in [
456
- functions_with_hash_key_filename,
457
- functions_with_tag_filename,
458
- ]:
459
- for function_name, filename_to_function_map in functions_map.items():
460
- results.extend(filename_to_function_map.values())
461
-
462
- return results
463
-
464
- def _filepath(self, table, project, key="", tag=""):
465
- if tag == "*":
466
- tag = ""
467
- if tag:
468
- key = "/" + key
469
- project = project or config.default_project
470
- return path.join(self.dirpath, table, project, tag + key)
471
-
472
- def list_projects(
473
- self,
474
- owner: str = None,
475
- format_: mlrun.api.schemas.ProjectsFormat = mlrun.api.schemas.ProjectsFormat.full,
476
- labels: List[str] = None,
477
- state: mlrun.api.schemas.ProjectState = None,
478
- names: Optional[List[str]] = None,
479
- ) -> mlrun.api.schemas.ProjectsOutput:
480
- if (
481
- owner
482
- or format_ == mlrun.api.schemas.ProjectsFormat.full
483
- or labels
484
- or state
485
- or names
486
- ):
487
- raise NotImplementedError()
488
- run_dir = path.join(self.dirpath, run_logs)
489
- if not path.isdir(run_dir):
490
- return mlrun.api.schemas.ProjectsOutput(projects=[])
491
- project_names = [
492
- d for d in listdir(run_dir) if path.isdir(path.join(run_dir, d))
493
- ]
494
- return mlrun.api.schemas.ProjectsOutput(projects=project_names)
495
-
496
- def tag_objects(
497
- self,
498
- project: str,
499
- tag_name: str,
500
- tag_objects: schemas.TagObjects,
501
- replace: bool = False,
502
- ):
503
- raise NotImplementedError()
504
-
505
- def delete_objects_tag(
506
- self, project: str, tag_name: str, tag_objects: schemas.TagObjects
507
- ):
508
- raise NotImplementedError()
509
-
510
- def tag_artifacts(
511
- self,
512
- artifacts,
513
- project: str,
514
- tag_name: str,
515
- replace: bool = False,
516
- ):
517
- raise NotImplementedError()
518
-
519
- def delete_artifacts_tags(
520
- self,
521
- artifacts,
522
- project: str,
523
- tag_name: str,
524
- ):
525
- raise NotImplementedError()
526
-
527
- def get_project(self, name: str) -> mlrun.api.schemas.Project:
528
- # returns None if project not found, mainly for tests, until we remove fileDB
529
- return None
530
-
531
- def delete_project(
532
- self,
533
- name: str,
534
- deletion_strategy: mlrun.api.schemas.DeletionStrategy = mlrun.api.schemas.DeletionStrategy.default(),
535
- ):
536
- raise NotImplementedError()
537
-
538
- def store_project(
539
- self,
540
- name: str,
541
- project: mlrun.api.schemas.Project,
542
- ) -> mlrun.api.schemas.Project:
543
- raise NotImplementedError()
544
-
545
- def patch_project(
546
- self,
547
- name: str,
548
- project: dict,
549
- patch_mode: mlrun.api.schemas.PatchMode = mlrun.api.schemas.PatchMode.replace,
550
- ) -> mlrun.api.schemas.Project:
551
- raise NotImplementedError()
552
-
553
- def create_project(
554
- self,
555
- project: mlrun.api.schemas.Project,
556
- ) -> mlrun.api.schemas.Project:
557
- if isinstance(project, dict):
558
- project = mlrun.api.schemas.Project(**project)
559
- self._projects[project.metadata.name] = project
560
- return project
561
-
562
- @property
563
- def schedules_dir(self):
564
- return path.join(self.dirpath, schedules_dir)
565
-
566
- def store_schedule(self, data):
567
- sched_id = 1 + sum(1 for _ in scandir(self.schedules_dir))
568
- fname = path.join(self.schedules_dir, f"{sched_id}{self.format}")
569
- with open(fname, "w") as out:
570
- out.write(self._dumps(data))
571
-
572
- def list_schedules(self):
573
- pattern = f"*{self.format}"
574
- for p in pathlib.Path(self.schedules_dir).glob(pattern):
575
- with p.open() as fp:
576
- yield self._loads(fp.read())
577
-
578
- return []
579
-
580
- _encodings = {
581
- ".yaml": ("to_yaml", dict_to_yaml),
582
- ".json": ("to_json", dict_to_json),
583
- }
584
-
585
- def _dumps(self, obj):
586
- meth_name, enc_fn = self._encodings.get(self.format, (None, None))
587
- if meth_name is None:
588
- raise ValueError(f"unsupported format - {self.format}")
589
-
590
- meth = getattr(obj, meth_name, None)
591
- if meth:
592
- return meth()
593
-
594
- return enc_fn(obj)
595
-
596
- def _loads(self, data):
597
- if self.format == ".yaml":
598
- return yaml.load(data, Loader=yaml.FullLoader)
599
- else:
600
- return json.loads(data)
601
-
602
- def _load_list(self, dirpath, mask):
603
- for p in pathlib.Path(dirpath).glob(mask + self.format):
604
- if p.is_file():
605
- if ".ipynb_checkpoints" in p.parts:
606
- continue
607
- data = self._loads(p.read_text())
608
- if data:
609
- yield data, str(p)
610
-
611
- def _safe_del(self, filepath):
612
- if path.isfile(filepath):
613
- remove(filepath)
614
- else:
615
- raise RunDBError(f"run file is not found or valid ({filepath})")
616
-
617
- def create_feature_set(self, feature_set, project="", versioned=True):
618
- raise NotImplementedError()
619
-
620
- def get_feature_set(
621
- self, name: str, project: str = "", tag: str = None, uid: str = None
622
- ):
623
- raise NotImplementedError()
624
-
625
- def list_features(
626
- self,
627
- project: str,
628
- name: str = None,
629
- tag: str = None,
630
- entities: List[str] = None,
631
- labels: List[str] = None,
632
- ):
633
- raise NotImplementedError()
634
-
635
- def list_entities(
636
- self,
637
- project: str,
638
- name: str = None,
639
- tag: str = None,
640
- labels: List[str] = None,
641
- ):
642
- raise NotImplementedError()
643
-
644
- def list_feature_sets(
645
- self,
646
- project: str = "",
647
- name: str = None,
648
- tag: str = None,
649
- state: str = None,
650
- entities: List[str] = None,
651
- features: List[str] = None,
652
- labels: List[str] = None,
653
- partition_by: str = None,
654
- rows_per_partition: int = 1,
655
- partition_sort_by: str = None,
656
- partition_order: str = "desc",
657
- ):
658
- raise NotImplementedError()
659
-
660
- def store_feature_set(
661
- self, feature_set, name=None, project="", tag=None, uid=None, versioned=True
662
- ):
663
- raise NotImplementedError()
664
-
665
- def patch_feature_set(
666
- self,
667
- name,
668
- feature_set,
669
- project="",
670
- tag=None,
671
- uid=None,
672
- patch_mode="replace",
673
- ):
674
- raise NotImplementedError()
675
-
676
- def delete_feature_set(self, name, project="", tag=None, uid=None):
677
- raise NotImplementedError()
678
-
679
- def create_feature_vector(self, feature_vector, project="", versioned=True) -> dict:
680
- raise NotImplementedError()
681
-
682
- def get_feature_vector(
683
- self, name: str, project: str = "", tag: str = None, uid: str = None
684
- ) -> dict:
685
- raise NotImplementedError()
686
-
687
- def list_feature_vectors(
688
- self,
689
- project: str = "",
690
- name: str = None,
691
- tag: str = None,
692
- state: str = None,
693
- labels: List[str] = None,
694
- partition_by: str = None,
695
- rows_per_partition: int = 1,
696
- partition_sort_by: str = None,
697
- partition_order: str = "desc",
698
- ) -> List[dict]:
699
- raise NotImplementedError()
700
-
701
- def store_feature_vector(
702
- self,
703
- feature_vector,
704
- name=None,
705
- project="",
706
- tag=None,
707
- uid=None,
708
- versioned=True,
709
- ):
710
- raise NotImplementedError()
711
-
712
- def patch_feature_vector(
713
- self,
714
- name,
715
- feature_vector_update: dict,
716
- project="",
717
- tag=None,
718
- uid=None,
719
- patch_mode="replace",
720
- ):
721
- raise NotImplementedError()
722
-
723
- def delete_feature_vector(self, name, project="", tag=None, uid=None):
724
- raise NotImplementedError()
725
-
726
- def list_pipelines(
727
- self,
728
- project: str,
729
- namespace: str = None,
730
- sort_by: str = "",
731
- page_token: str = "",
732
- filter_: str = "",
733
- format_: Union[
734
- str, mlrun.api.schemas.PipelinesFormat
735
- ] = mlrun.api.schemas.PipelinesFormat.metadata_only,
736
- page_size: int = None,
737
- ) -> mlrun.api.schemas.PipelinesOutput:
738
- raise NotImplementedError()
739
-
740
- def create_project_secrets(
741
- self,
742
- project: str,
743
- provider: str = mlrun.api.schemas.SecretProviderName.kubernetes.value,
744
- secrets: dict = None,
745
- ):
746
- for key, value in secrets.items():
747
- self._secrets._secrets[key] = value
748
-
749
- def list_project_secrets(
750
- self,
751
- project: str,
752
- token: str,
753
- provider: str = mlrun.api.schemas.SecretProviderName.kubernetes.value,
754
- secrets: List[str] = None,
755
- ) -> mlrun.api.schemas.SecretsData:
756
- raise NotImplementedError()
757
-
758
- def list_project_secret_keys(
759
- self,
760
- project: str,
761
- provider: str = mlrun.api.schemas.SecretProviderName.kubernetes,
762
- token: str = None,
763
- ) -> mlrun.api.schemas.SecretKeysData:
764
- raise NotImplementedError()
765
-
766
- def delete_project_secrets(
767
- self,
768
- project: str,
769
- provider: str = mlrun.api.schemas.SecretProviderName.kubernetes.value,
770
- secrets: List[str] = None,
771
- ):
772
- raise NotImplementedError()
773
-
774
- def create_user_secrets(
775
- self,
776
- user: str,
777
- provider: str = mlrun.api.schemas.secret.SecretProviderName.vault.value,
778
- secrets: dict = None,
779
- ):
780
- raise NotImplementedError()
781
-
782
- def list_artifact_tags(self, project=None, category=None):
783
- raise NotImplementedError()
784
-
785
- def create_model_endpoint(
786
- self,
787
- project: str,
788
- endpoint_id: str,
789
- model_endpoint: Union[
790
- mlrun.model_monitoring.model_endpoint.ModelEndpoint, dict
791
- ],
792
- ):
793
- raise NotImplementedError()
794
-
795
- def delete_model_endpoint(
796
- self,
797
- project: str,
798
- endpoint_id: str,
799
- ):
800
- raise NotImplementedError()
801
-
802
- def list_model_endpoints(
803
- self,
804
- project: str,
805
- model: Optional[str] = None,
806
- function: Optional[str] = None,
807
- labels: List[str] = None,
808
- start: str = "now-1h",
809
- end: str = "now",
810
- metrics: Optional[List[str]] = None,
811
- ):
812
- raise NotImplementedError()
813
-
814
- def get_model_endpoint(
815
- self,
816
- project: str,
817
- endpoint_id: str,
818
- start: Optional[str] = None,
819
- end: Optional[str] = None,
820
- metrics: Optional[List[str]] = None,
821
- features: bool = False,
822
- ):
823
- raise NotImplementedError()
824
-
825
- def patch_model_endpoint(
826
- self,
827
- project: str,
828
- endpoint_id: str,
829
- attributes: dict,
830
- ):
831
- raise NotImplementedError()
832
-
833
- def create_marketplace_source(
834
- self, source: Union[dict, schemas.IndexedMarketplaceSource]
835
- ):
836
- raise NotImplementedError()
837
-
838
- def store_marketplace_source(
839
- self, source_name: str, source: Union[dict, schemas.IndexedMarketplaceSource]
840
- ):
841
- raise NotImplementedError()
842
-
843
- def list_marketplace_sources(self):
844
- raise NotImplementedError()
845
-
846
- def get_marketplace_source(self, source_name: str):
847
- raise NotImplementedError()
848
-
849
- def delete_marketplace_source(self, source_name: str):
850
- raise NotImplementedError()
851
-
852
- def get_marketplace_catalog(
853
- self,
854
- source_name: str,
855
- channel: str = None,
856
- version: str = None,
857
- tag: str = None,
858
- force_refresh: bool = False,
859
- ):
860
- raise NotImplementedError()
861
-
862
- def get_marketplace_item(
863
- self,
864
- source_name: str,
865
- item_name: str,
866
- channel: str = "development",
867
- version: str = None,
868
- tag: str = "latest",
869
- force_refresh: bool = False,
870
- ):
871
- raise NotImplementedError()
872
-
873
- def verify_authorization(
874
- self,
875
- authorization_verification_input: mlrun.api.schemas.AuthorizationVerificationInput,
876
- ):
877
- raise NotImplementedError()
878
-
879
-
880
- def make_time_pred(since, until):
881
- if not (since or until):
882
- return lambda artifact: True
883
-
884
- since = since or datetime.min
885
- until = until or datetime.max
886
-
887
- if since.tzinfo is None:
888
- since = since.replace(tzinfo=timezone.utc)
889
- if until.tzinfo is None:
890
- until = until.replace(tzinfo=timezone.utc)
891
-
892
- def pred(artifact):
893
- val = artifact.get("updated")
894
- if not val:
895
- return True
896
- t = parse_time(val).replace(tzinfo=timezone.utc)
897
- return since <= t <= until
898
-
899
- return pred