mlrun 1.3.2rc1__py3-none-any.whl → 1.3.2rc2__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/api/api/deps.py +14 -1
- mlrun/api/api/endpoints/frontend_spec.py +0 -2
- mlrun/api/api/endpoints/functions.py +15 -27
- mlrun/api/api/endpoints/grafana_proxy.py +435 -74
- mlrun/api/api/endpoints/healthz.py +5 -18
- mlrun/api/api/endpoints/model_endpoints.py +33 -37
- mlrun/api/api/utils.py +6 -13
- mlrun/api/crud/__init__.py +14 -16
- mlrun/api/crud/logs.py +5 -7
- mlrun/api/crud/model_monitoring/__init__.py +2 -2
- mlrun/api/crud/model_monitoring/model_endpoint_store.py +847 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +105 -328
- mlrun/api/crud/pipelines.py +2 -3
- mlrun/api/db/sqldb/models/models_mysql.py +52 -19
- mlrun/api/db/sqldb/models/models_sqlite.py +52 -19
- mlrun/api/db/sqldb/session.py +19 -26
- mlrun/api/schemas/__init__.py +2 -0
- mlrun/api/schemas/constants.py +0 -13
- mlrun/api/schemas/frontend_spec.py +0 -1
- mlrun/api/schemas/model_endpoints.py +38 -195
- mlrun/api/schemas/schedule.py +2 -2
- mlrun/api/utils/clients/log_collector.py +5 -0
- mlrun/builder.py +9 -41
- mlrun/config.py +1 -76
- mlrun/data_types/__init__.py +1 -6
- mlrun/data_types/data_types.py +1 -3
- mlrun/datastore/__init__.py +2 -9
- mlrun/datastore/sources.py +20 -25
- mlrun/datastore/store_resources.py +1 -1
- mlrun/datastore/targets.py +34 -67
- mlrun/datastore/utils.py +4 -26
- mlrun/db/base.py +2 -4
- mlrun/db/filedb.py +5 -13
- mlrun/db/httpdb.py +32 -64
- mlrun/db/sqldb.py +2 -4
- mlrun/errors.py +0 -5
- mlrun/execution.py +0 -2
- mlrun/feature_store/api.py +8 -24
- mlrun/feature_store/feature_set.py +6 -28
- mlrun/feature_store/feature_vector.py +0 -2
- mlrun/feature_store/ingestion.py +11 -8
- mlrun/feature_store/retrieval/base.py +43 -271
- mlrun/feature_store/retrieval/dask_merger.py +153 -55
- mlrun/feature_store/retrieval/job.py +3 -12
- mlrun/feature_store/retrieval/local_merger.py +130 -48
- mlrun/feature_store/retrieval/spark_merger.py +125 -126
- mlrun/features.py +2 -7
- mlrun/model_monitoring/constants.py +6 -48
- mlrun/model_monitoring/helpers.py +35 -118
- mlrun/model_monitoring/model_monitoring_batch.py +260 -293
- mlrun/model_monitoring/stream_processing_fs.py +253 -220
- mlrun/platforms/iguazio.py +0 -33
- mlrun/projects/project.py +72 -34
- mlrun/runtimes/base.py +0 -5
- mlrun/runtimes/daskjob.py +0 -2
- mlrun/runtimes/function.py +3 -29
- mlrun/runtimes/kubejob.py +15 -39
- mlrun/runtimes/local.py +45 -7
- mlrun/runtimes/mpijob/abstract.py +0 -2
- mlrun/runtimes/mpijob/v1.py +0 -2
- mlrun/runtimes/pod.py +0 -2
- mlrun/runtimes/remotesparkjob.py +0 -2
- mlrun/runtimes/serving.py +0 -6
- mlrun/runtimes/sparkjob/abstract.py +2 -39
- mlrun/runtimes/sparkjob/spark3job.py +0 -2
- mlrun/serving/__init__.py +1 -2
- mlrun/serving/routers.py +35 -35
- mlrun/serving/server.py +12 -22
- mlrun/serving/states.py +30 -162
- mlrun/serving/v2_serving.py +10 -13
- mlrun/utils/clones.py +1 -1
- mlrun/utils/model_monitoring.py +96 -122
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/METADATA +27 -23
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/RECORD +79 -92
- mlrun/api/crud/model_monitoring/grafana.py +0 -427
- mlrun/datastore/spark_udf.py +0 -40
- mlrun/model_monitoring/__init__.py +0 -44
- mlrun/model_monitoring/common.py +0 -112
- mlrun/model_monitoring/model_endpoint.py +0 -141
- mlrun/model_monitoring/stores/__init__.py +0 -106
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -448
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
- mlrun/model_monitoring/stores/models/__init__.py +0 -23
- mlrun/model_monitoring/stores/models/base.py +0 -18
- mlrun/model_monitoring/stores/models/mysql.py +0 -100
- mlrun/model_monitoring/stores/models/sqlite.py +0 -98
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -375
- mlrun/utils/db.py +0 -52
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/LICENSE +0 -0
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/WHEEL +0 -0
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/top_level.txt +0 -0
mlrun/api/crud/pipelines.py
CHANGED
|
@@ -47,9 +47,9 @@ class Pipelines(
|
|
|
47
47
|
format_: mlrun.api.schemas.PipelinesFormat = mlrun.api.schemas.PipelinesFormat.metadata_only,
|
|
48
48
|
page_size: typing.Optional[int] = None,
|
|
49
49
|
) -> typing.Tuple[int, typing.Optional[int], typing.List[dict]]:
|
|
50
|
-
if project != "*" and (page_token or page_size):
|
|
50
|
+
if project != "*" and (page_token or page_size or sort_by):
|
|
51
51
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
52
|
-
"Filtering by project can not be used together with pagination"
|
|
52
|
+
"Filtering by project can not be used together with pagination, or sorting"
|
|
53
53
|
)
|
|
54
54
|
if format_ == mlrun.api.schemas.PipelinesFormat.summary:
|
|
55
55
|
# we don't support summary format in list pipelines since the returned runs doesn't include the workflow
|
|
@@ -73,7 +73,6 @@ class Pipelines(
|
|
|
73
73
|
response = kfp_client._run_api.list_runs(
|
|
74
74
|
page_token=page_token,
|
|
75
75
|
page_size=mlrun.api.schemas.PipelinesPagination.max_page_size,
|
|
76
|
-
sort_by=sort_by,
|
|
77
76
|
filter=filter_ if page_token == "" else "",
|
|
78
77
|
)
|
|
79
78
|
run_dicts.extend([run.to_dict() for run in response.runs or []])
|
|
@@ -30,9 +30,8 @@ from sqlalchemy import (
|
|
|
30
30
|
UniqueConstraint,
|
|
31
31
|
)
|
|
32
32
|
from sqlalchemy.ext.declarative import declarative_base
|
|
33
|
-
from sqlalchemy.orm import relationship
|
|
33
|
+
from sqlalchemy.orm import class_mapper, relationship
|
|
34
34
|
|
|
35
|
-
import mlrun.utils.db
|
|
36
35
|
from mlrun.api import schemas
|
|
37
36
|
from mlrun.api.utils.db.sql_collation import SQLCollationUtil
|
|
38
37
|
|
|
@@ -41,8 +40,42 @@ NULL = None # Avoid flake8 issuing warnings when comparing in filter
|
|
|
41
40
|
run_time_fmt = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
42
41
|
|
|
43
42
|
|
|
43
|
+
class BaseModel:
|
|
44
|
+
def to_dict(self, exclude=None):
|
|
45
|
+
"""
|
|
46
|
+
NOTE - this function (currently) does not handle serializing relationships
|
|
47
|
+
"""
|
|
48
|
+
exclude = exclude or []
|
|
49
|
+
mapper = class_mapper(self.__class__)
|
|
50
|
+
columns = [column.key for column in mapper.columns if column.key not in exclude]
|
|
51
|
+
get_key_value = (
|
|
52
|
+
lambda c: (c, getattr(self, c).isoformat())
|
|
53
|
+
if isinstance(getattr(self, c), datetime)
|
|
54
|
+
else (c, getattr(self, c))
|
|
55
|
+
)
|
|
56
|
+
return dict(map(get_key_value, columns))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class HasStruct(BaseModel):
|
|
60
|
+
@property
|
|
61
|
+
def struct(self):
|
|
62
|
+
return pickle.loads(self.body)
|
|
63
|
+
|
|
64
|
+
@struct.setter
|
|
65
|
+
def struct(self, value):
|
|
66
|
+
self.body = pickle.dumps(value)
|
|
67
|
+
|
|
68
|
+
def to_dict(self, exclude=None):
|
|
69
|
+
"""
|
|
70
|
+
NOTE - this function (currently) does not handle serializing relationships
|
|
71
|
+
"""
|
|
72
|
+
exclude = exclude or []
|
|
73
|
+
exclude.append("body")
|
|
74
|
+
return super().to_dict(exclude)
|
|
75
|
+
|
|
76
|
+
|
|
44
77
|
def make_label(table):
|
|
45
|
-
class Label(Base,
|
|
78
|
+
class Label(Base, BaseModel):
|
|
46
79
|
__tablename__ = f"{table}_labels"
|
|
47
80
|
__table_args__ = (
|
|
48
81
|
UniqueConstraint("name", "parent", name=f"_{table}_labels_uc"),
|
|
@@ -57,7 +90,7 @@ def make_label(table):
|
|
|
57
90
|
|
|
58
91
|
|
|
59
92
|
def make_tag(table):
|
|
60
|
-
class Tag(Base,
|
|
93
|
+
class Tag(Base, BaseModel):
|
|
61
94
|
__tablename__ = f"{table}_tags"
|
|
62
95
|
__table_args__ = (
|
|
63
96
|
UniqueConstraint("project", "name", "obj_id", name=f"_{table}_tags_uc"),
|
|
@@ -74,7 +107,7 @@ def make_tag(table):
|
|
|
74
107
|
# TODO: don't want to refactor everything in one PR so splitting this function to 2 versions - eventually only this one
|
|
75
108
|
# should be used
|
|
76
109
|
def make_tag_v2(table):
|
|
77
|
-
class Tag(Base,
|
|
110
|
+
class Tag(Base, BaseModel):
|
|
78
111
|
__tablename__ = f"{table}_tags"
|
|
79
112
|
__table_args__ = (
|
|
80
113
|
UniqueConstraint("project", "name", "obj_name", name=f"_{table}_tags_uc"),
|
|
@@ -93,7 +126,7 @@ def make_tag_v2(table):
|
|
|
93
126
|
with warnings.catch_warnings():
|
|
94
127
|
warnings.simplefilter("ignore")
|
|
95
128
|
|
|
96
|
-
class Artifact(Base,
|
|
129
|
+
class Artifact(Base, HasStruct):
|
|
97
130
|
__tablename__ = "artifacts"
|
|
98
131
|
__table_args__ = (
|
|
99
132
|
UniqueConstraint("uid", "project", "key", name="_artifacts_uc"),
|
|
@@ -116,7 +149,7 @@ with warnings.catch_warnings():
|
|
|
116
149
|
def get_identifier_string(self) -> str:
|
|
117
150
|
return f"{self.project}/{self.key}/{self.uid}"
|
|
118
151
|
|
|
119
|
-
class Function(Base,
|
|
152
|
+
class Function(Base, HasStruct):
|
|
120
153
|
__tablename__ = "functions"
|
|
121
154
|
__table_args__ = (
|
|
122
155
|
UniqueConstraint("name", "project", "uid", name="_functions_uc"),
|
|
@@ -139,7 +172,7 @@ with warnings.catch_warnings():
|
|
|
139
172
|
def get_identifier_string(self) -> str:
|
|
140
173
|
return f"{self.project}/{self.name}/{self.uid}"
|
|
141
174
|
|
|
142
|
-
class Log(Base,
|
|
175
|
+
class Log(Base, BaseModel):
|
|
143
176
|
__tablename__ = "logs"
|
|
144
177
|
|
|
145
178
|
id = Column(Integer, primary_key=True)
|
|
@@ -151,7 +184,7 @@ with warnings.catch_warnings():
|
|
|
151
184
|
def get_identifier_string(self) -> str:
|
|
152
185
|
return f"{self.project}/{self.uid}"
|
|
153
186
|
|
|
154
|
-
class Run(Base,
|
|
187
|
+
class Run(Base, HasStruct):
|
|
155
188
|
__tablename__ = "runs"
|
|
156
189
|
__table_args__ = (
|
|
157
190
|
UniqueConstraint("uid", "project", "iteration", name="_runs_uc"),
|
|
@@ -186,7 +219,7 @@ with warnings.catch_warnings():
|
|
|
186
219
|
def get_identifier_string(self) -> str:
|
|
187
220
|
return f"{self.project}/{self.uid}/{self.iteration}"
|
|
188
221
|
|
|
189
|
-
class BackgroundTask(Base,
|
|
222
|
+
class BackgroundTask(Base, BaseModel):
|
|
190
223
|
__tablename__ = "background_tasks"
|
|
191
224
|
__table_args__ = (
|
|
192
225
|
UniqueConstraint("name", "project", name="_background_tasks_uc"),
|
|
@@ -210,7 +243,7 @@ with warnings.catch_warnings():
|
|
|
210
243
|
state = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
211
244
|
timeout = Column(Integer)
|
|
212
245
|
|
|
213
|
-
class Schedule(Base,
|
|
246
|
+
class Schedule(Base, BaseModel):
|
|
214
247
|
__tablename__ = "schedules_v2"
|
|
215
248
|
__table_args__ = (UniqueConstraint("project", "name", name="_schedules_v2_uc"),)
|
|
216
249
|
|
|
@@ -262,14 +295,14 @@ with warnings.catch_warnings():
|
|
|
262
295
|
Column("user_id", Integer, ForeignKey("users.id")),
|
|
263
296
|
)
|
|
264
297
|
|
|
265
|
-
class User(Base,
|
|
298
|
+
class User(Base, BaseModel):
|
|
266
299
|
__tablename__ = "users"
|
|
267
300
|
__table_args__ = (UniqueConstraint("name", name="_users_uc"),)
|
|
268
301
|
|
|
269
302
|
id = Column(Integer, primary_key=True)
|
|
270
303
|
name = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
271
304
|
|
|
272
|
-
class Project(Base,
|
|
305
|
+
class Project(Base, BaseModel):
|
|
273
306
|
__tablename__ = "projects"
|
|
274
307
|
# For now since we use project name a lot
|
|
275
308
|
__table_args__ = (UniqueConstraint("name", name="_projects_uc"),)
|
|
@@ -305,7 +338,7 @@ with warnings.catch_warnings():
|
|
|
305
338
|
def full_object(self, value):
|
|
306
339
|
self._full_object = pickle.dumps(value)
|
|
307
340
|
|
|
308
|
-
class Feature(Base,
|
|
341
|
+
class Feature(Base, BaseModel):
|
|
309
342
|
__tablename__ = "features"
|
|
310
343
|
id = Column(Integer, primary_key=True)
|
|
311
344
|
feature_set_id = Column(Integer, ForeignKey("feature_sets.id"))
|
|
@@ -319,7 +352,7 @@ with warnings.catch_warnings():
|
|
|
319
352
|
def get_identifier_string(self) -> str:
|
|
320
353
|
return f"{self.project}/{self.name}"
|
|
321
354
|
|
|
322
|
-
class Entity(Base,
|
|
355
|
+
class Entity(Base, BaseModel):
|
|
323
356
|
__tablename__ = "entities"
|
|
324
357
|
id = Column(Integer, primary_key=True)
|
|
325
358
|
feature_set_id = Column(Integer, ForeignKey("feature_sets.id"))
|
|
@@ -333,7 +366,7 @@ with warnings.catch_warnings():
|
|
|
333
366
|
def get_identifier_string(self) -> str:
|
|
334
367
|
return f"{self.project}/{self.name}"
|
|
335
368
|
|
|
336
|
-
class FeatureSet(Base,
|
|
369
|
+
class FeatureSet(Base, BaseModel):
|
|
337
370
|
__tablename__ = "feature_sets"
|
|
338
371
|
__table_args__ = (
|
|
339
372
|
UniqueConstraint("name", "project", "uid", name="_feature_set_uc"),
|
|
@@ -377,7 +410,7 @@ with warnings.catch_warnings():
|
|
|
377
410
|
# TODO - convert to pickle, to avoid issues with non-json serializable fields such as datetime
|
|
378
411
|
self._full_object = json.dumps(value, default=str)
|
|
379
412
|
|
|
380
|
-
class FeatureVector(Base,
|
|
413
|
+
class FeatureVector(Base, BaseModel):
|
|
381
414
|
__tablename__ = "feature_vectors"
|
|
382
415
|
__table_args__ = (
|
|
383
416
|
UniqueConstraint("name", "project", "uid", name="_feature_vectors_uc"),
|
|
@@ -418,7 +451,7 @@ with warnings.catch_warnings():
|
|
|
418
451
|
# TODO - convert to pickle, to avoid issues with non-json serializable fields such as datetime
|
|
419
452
|
self._full_object = json.dumps(value, default=str)
|
|
420
453
|
|
|
421
|
-
class MarketplaceSource(Base,
|
|
454
|
+
class MarketplaceSource(Base, BaseModel):
|
|
422
455
|
__tablename__ = "marketplace_sources"
|
|
423
456
|
__table_args__ = (UniqueConstraint("name", name="_marketplace_sources_uc"),)
|
|
424
457
|
|
|
@@ -449,7 +482,7 @@ with warnings.catch_warnings():
|
|
|
449
482
|
# TODO - convert to pickle, to avoid issues with non-json serializable fields such as datetime
|
|
450
483
|
self._full_object = json.dumps(value, default=str)
|
|
451
484
|
|
|
452
|
-
class DataVersion(Base,
|
|
485
|
+
class DataVersion(Base, BaseModel):
|
|
453
486
|
__tablename__ = "data_versions"
|
|
454
487
|
__table_args__ = (UniqueConstraint("version", name="_versions_uc"),)
|
|
455
488
|
|
|
@@ -31,9 +31,8 @@ from sqlalchemy import (
|
|
|
31
31
|
UniqueConstraint,
|
|
32
32
|
)
|
|
33
33
|
from sqlalchemy.ext.declarative import declarative_base
|
|
34
|
-
from sqlalchemy.orm import relationship
|
|
34
|
+
from sqlalchemy.orm import class_mapper, relationship
|
|
35
35
|
|
|
36
|
-
import mlrun.utils.db
|
|
37
36
|
from mlrun.api import schemas
|
|
38
37
|
from mlrun.api.utils.db.sql_collation import SQLCollationUtil
|
|
39
38
|
|
|
@@ -42,8 +41,42 @@ NULL = None # Avoid flake8 issuing warnings when comparing in filter
|
|
|
42
41
|
run_time_fmt = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
43
42
|
|
|
44
43
|
|
|
44
|
+
class BaseModel:
|
|
45
|
+
def to_dict(self, exclude=None):
|
|
46
|
+
"""
|
|
47
|
+
NOTE - this function (currently) does not handle serializing relationships
|
|
48
|
+
"""
|
|
49
|
+
exclude = exclude or []
|
|
50
|
+
mapper = class_mapper(self.__class__)
|
|
51
|
+
columns = [column.key for column in mapper.columns if column.key not in exclude]
|
|
52
|
+
get_key_value = (
|
|
53
|
+
lambda c: (c, getattr(self, c).isoformat())
|
|
54
|
+
if isinstance(getattr(self, c), datetime)
|
|
55
|
+
else (c, getattr(self, c))
|
|
56
|
+
)
|
|
57
|
+
return dict(map(get_key_value, columns))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class HasStruct(BaseModel):
|
|
61
|
+
@property
|
|
62
|
+
def struct(self):
|
|
63
|
+
return pickle.loads(self.body)
|
|
64
|
+
|
|
65
|
+
@struct.setter
|
|
66
|
+
def struct(self, value):
|
|
67
|
+
self.body = pickle.dumps(value)
|
|
68
|
+
|
|
69
|
+
def to_dict(self, exclude=None):
|
|
70
|
+
"""
|
|
71
|
+
NOTE - this function (currently) does not handle serializing relationships
|
|
72
|
+
"""
|
|
73
|
+
exclude = exclude or []
|
|
74
|
+
exclude.append("body")
|
|
75
|
+
return super().to_dict(exclude)
|
|
76
|
+
|
|
77
|
+
|
|
45
78
|
def make_label(table):
|
|
46
|
-
class Label(Base,
|
|
79
|
+
class Label(Base, BaseModel):
|
|
47
80
|
__tablename__ = f"{table}_labels"
|
|
48
81
|
__table_args__ = (
|
|
49
82
|
UniqueConstraint("name", "parent", name=f"_{table}_labels_uc"),
|
|
@@ -58,7 +91,7 @@ def make_label(table):
|
|
|
58
91
|
|
|
59
92
|
|
|
60
93
|
def make_tag(table):
|
|
61
|
-
class Tag(Base,
|
|
94
|
+
class Tag(Base, BaseModel):
|
|
62
95
|
__tablename__ = f"{table}_tags"
|
|
63
96
|
__table_args__ = (
|
|
64
97
|
UniqueConstraint("project", "name", "obj_id", name=f"_{table}_tags_uc"),
|
|
@@ -75,7 +108,7 @@ def make_tag(table):
|
|
|
75
108
|
# TODO: don't want to refactor everything in one PR so splitting this function to 2 versions - eventually only this one
|
|
76
109
|
# should be used
|
|
77
110
|
def make_tag_v2(table):
|
|
78
|
-
class Tag(Base,
|
|
111
|
+
class Tag(Base, BaseModel):
|
|
79
112
|
__tablename__ = f"{table}_tags"
|
|
80
113
|
__table_args__ = (
|
|
81
114
|
UniqueConstraint("project", "name", "obj_name", name=f"_{table}_tags_uc"),
|
|
@@ -97,7 +130,7 @@ def make_tag_v2(table):
|
|
|
97
130
|
with warnings.catch_warnings():
|
|
98
131
|
warnings.simplefilter("ignore")
|
|
99
132
|
|
|
100
|
-
class Artifact(Base,
|
|
133
|
+
class Artifact(Base, HasStruct):
|
|
101
134
|
__tablename__ = "artifacts"
|
|
102
135
|
__table_args__ = (
|
|
103
136
|
UniqueConstraint("uid", "project", "key", name="_artifacts_uc"),
|
|
@@ -118,7 +151,7 @@ with warnings.catch_warnings():
|
|
|
118
151
|
def get_identifier_string(self) -> str:
|
|
119
152
|
return f"{self.project}/{self.key}/{self.uid}"
|
|
120
153
|
|
|
121
|
-
class Function(Base,
|
|
154
|
+
class Function(Base, HasStruct):
|
|
122
155
|
__tablename__ = "functions"
|
|
123
156
|
__table_args__ = (
|
|
124
157
|
UniqueConstraint("name", "project", "uid", name="_functions_uc"),
|
|
@@ -139,7 +172,7 @@ with warnings.catch_warnings():
|
|
|
139
172
|
def get_identifier_string(self) -> str:
|
|
140
173
|
return f"{self.project}/{self.name}/{self.uid}"
|
|
141
174
|
|
|
142
|
-
class Log(Base,
|
|
175
|
+
class Log(Base, BaseModel):
|
|
143
176
|
__tablename__ = "logs"
|
|
144
177
|
|
|
145
178
|
id = Column(Integer, primary_key=True)
|
|
@@ -151,7 +184,7 @@ with warnings.catch_warnings():
|
|
|
151
184
|
def get_identifier_string(self) -> str:
|
|
152
185
|
return f"{self.project}/{self.uid}"
|
|
153
186
|
|
|
154
|
-
class Run(Base,
|
|
187
|
+
class Run(Base, HasStruct):
|
|
155
188
|
__tablename__ = "runs"
|
|
156
189
|
__table_args__ = (
|
|
157
190
|
UniqueConstraint("uid", "project", "iteration", name="_runs_uc"),
|
|
@@ -182,7 +215,7 @@ with warnings.catch_warnings():
|
|
|
182
215
|
def get_identifier_string(self) -> str:
|
|
183
216
|
return f"{self.project}/{self.uid}/{self.iteration}"
|
|
184
217
|
|
|
185
|
-
class BackgroundTask(Base,
|
|
218
|
+
class BackgroundTask(Base, BaseModel):
|
|
186
219
|
__tablename__ = "background_tasks"
|
|
187
220
|
__table_args__ = (
|
|
188
221
|
UniqueConstraint("name", "project", name="_background_tasks_uc"),
|
|
@@ -200,7 +233,7 @@ with warnings.catch_warnings():
|
|
|
200
233
|
state = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
201
234
|
timeout = Column(Integer)
|
|
202
235
|
|
|
203
|
-
class Schedule(Base,
|
|
236
|
+
class Schedule(Base, BaseModel):
|
|
204
237
|
__tablename__ = "schedules_v2"
|
|
205
238
|
__table_args__ = (UniqueConstraint("project", "name", name="_schedules_v2_uc"),)
|
|
206
239
|
|
|
@@ -252,14 +285,14 @@ with warnings.catch_warnings():
|
|
|
252
285
|
Column("user_id", Integer, ForeignKey("users.id")),
|
|
253
286
|
)
|
|
254
287
|
|
|
255
|
-
class User(Base,
|
|
288
|
+
class User(Base, BaseModel):
|
|
256
289
|
__tablename__ = "users"
|
|
257
290
|
__table_args__ = (UniqueConstraint("name", name="_users_uc"),)
|
|
258
291
|
|
|
259
292
|
id = Column(Integer, primary_key=True)
|
|
260
293
|
name = Column(String(255, collation=SQLCollationUtil.collation()))
|
|
261
294
|
|
|
262
|
-
class Project(Base,
|
|
295
|
+
class Project(Base, BaseModel):
|
|
263
296
|
__tablename__ = "projects"
|
|
264
297
|
# For now since we use project name a lot
|
|
265
298
|
__table_args__ = (UniqueConstraint("name", name="_projects_uc"),)
|
|
@@ -293,7 +326,7 @@ with warnings.catch_warnings():
|
|
|
293
326
|
def full_object(self, value):
|
|
294
327
|
self._full_object = pickle.dumps(value)
|
|
295
328
|
|
|
296
|
-
class Feature(Base,
|
|
329
|
+
class Feature(Base, BaseModel):
|
|
297
330
|
__tablename__ = "features"
|
|
298
331
|
id = Column(Integer, primary_key=True)
|
|
299
332
|
feature_set_id = Column(Integer, ForeignKey("feature_sets.id"))
|
|
@@ -307,7 +340,7 @@ with warnings.catch_warnings():
|
|
|
307
340
|
def get_identifier_string(self) -> str:
|
|
308
341
|
return f"{self.project}/{self.name}"
|
|
309
342
|
|
|
310
|
-
class Entity(Base,
|
|
343
|
+
class Entity(Base, BaseModel):
|
|
311
344
|
__tablename__ = "entities"
|
|
312
345
|
id = Column(Integer, primary_key=True)
|
|
313
346
|
feature_set_id = Column(Integer, ForeignKey("feature_sets.id"))
|
|
@@ -321,7 +354,7 @@ with warnings.catch_warnings():
|
|
|
321
354
|
def get_identifier_string(self) -> str:
|
|
322
355
|
return f"{self.project}/{self.name}"
|
|
323
356
|
|
|
324
|
-
class FeatureSet(Base,
|
|
357
|
+
class FeatureSet(Base, BaseModel):
|
|
325
358
|
__tablename__ = "feature_sets"
|
|
326
359
|
__table_args__ = (
|
|
327
360
|
UniqueConstraint("name", "project", "uid", name="_feature_set_uc"),
|
|
@@ -357,7 +390,7 @@ with warnings.catch_warnings():
|
|
|
357
390
|
def full_object(self, value):
|
|
358
391
|
self._full_object = json.dumps(value, default=str)
|
|
359
392
|
|
|
360
|
-
class FeatureVector(Base,
|
|
393
|
+
class FeatureVector(Base, BaseModel):
|
|
361
394
|
__tablename__ = "feature_vectors"
|
|
362
395
|
__table_args__ = (
|
|
363
396
|
UniqueConstraint("name", "project", "uid", name="_feature_vectors_uc"),
|
|
@@ -390,7 +423,7 @@ with warnings.catch_warnings():
|
|
|
390
423
|
def full_object(self, value):
|
|
391
424
|
self._full_object = json.dumps(value, default=str)
|
|
392
425
|
|
|
393
|
-
class MarketplaceSource(Base,
|
|
426
|
+
class MarketplaceSource(Base, BaseModel):
|
|
394
427
|
__tablename__ = "marketplace_sources"
|
|
395
428
|
__table_args__ = (UniqueConstraint("name", name="_marketplace_sources_uc"),)
|
|
396
429
|
|
|
@@ -414,7 +447,7 @@ with warnings.catch_warnings():
|
|
|
414
447
|
def full_object(self, value):
|
|
415
448
|
self._full_object = json.dumps(value, default=str)
|
|
416
449
|
|
|
417
|
-
class DataVersion(Base,
|
|
450
|
+
class DataVersion(Base, BaseModel):
|
|
418
451
|
__tablename__ = "data_versions"
|
|
419
452
|
__table_args__ = (UniqueConstraint("version", name="_versions_uc"),)
|
|
420
453
|
|
mlrun/api/db/sqldb/session.py
CHANGED
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
|
-
|
|
16
|
-
import typing
|
|
17
|
-
|
|
18
15
|
from sqlalchemy import create_engine
|
|
19
16
|
from sqlalchemy.engine import Engine
|
|
20
17
|
from sqlalchemy.orm import Session
|
|
@@ -22,38 +19,35 @@ from sqlalchemy.orm import sessionmaker as SessionMaker
|
|
|
22
19
|
|
|
23
20
|
from mlrun.config import config
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
_session_makers: typing.Dict[str, SessionMaker] = {}
|
|
22
|
+
engine: Engine = None
|
|
23
|
+
_session_maker: SessionMaker = None
|
|
28
24
|
|
|
29
25
|
|
|
30
26
|
# doing lazy load to allow tests to initialize the engine
|
|
31
|
-
def get_engine(
|
|
32
|
-
global
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return _engines[dsn]
|
|
27
|
+
def get_engine() -> Engine:
|
|
28
|
+
global engine
|
|
29
|
+
if engine is None:
|
|
30
|
+
_init_engine()
|
|
31
|
+
return engine
|
|
37
32
|
|
|
38
33
|
|
|
39
|
-
def create_session(
|
|
40
|
-
session_maker = _get_session_maker(
|
|
34
|
+
def create_session() -> Session:
|
|
35
|
+
session_maker = _get_session_maker()
|
|
41
36
|
return session_maker()
|
|
42
37
|
|
|
43
38
|
|
|
44
39
|
# doing lazy load to allow tests to initialize the engine
|
|
45
|
-
def _get_session_maker(
|
|
46
|
-
global
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return _session_makers[dsn]
|
|
40
|
+
def _get_session_maker() -> SessionMaker:
|
|
41
|
+
global _session_maker
|
|
42
|
+
if _session_maker is None:
|
|
43
|
+
_init_session_maker()
|
|
44
|
+
return _session_maker
|
|
51
45
|
|
|
52
46
|
|
|
53
47
|
# TODO: we accept the dsn here to enable tests to override it, the "right" thing will be that config will be easily
|
|
54
48
|
# overridable by tests (today when you import the config it is already being initialized.. should be lazy load)
|
|
55
49
|
def _init_engine(dsn=None):
|
|
56
|
-
global
|
|
50
|
+
global engine
|
|
57
51
|
dsn = dsn or config.httpdb.dsn
|
|
58
52
|
kwargs = {}
|
|
59
53
|
if "mysql" in dsn:
|
|
@@ -68,10 +62,9 @@ def _init_engine(dsn=None):
|
|
|
68
62
|
"max_overflow": max_overflow,
|
|
69
63
|
}
|
|
70
64
|
engine = create_engine(dsn, **kwargs)
|
|
71
|
-
|
|
72
|
-
_init_session_maker(dsn=dsn)
|
|
65
|
+
_init_session_maker()
|
|
73
66
|
|
|
74
67
|
|
|
75
|
-
def _init_session_maker(
|
|
76
|
-
global
|
|
77
|
-
|
|
68
|
+
def _init_session_maker():
|
|
69
|
+
global _session_maker
|
|
70
|
+
_session_maker = SessionMaker(bind=get_engine())
|
mlrun/api/schemas/__init__.py
CHANGED
|
@@ -100,11 +100,13 @@ from .model_endpoints import (
|
|
|
100
100
|
GrafanaStringColumn,
|
|
101
101
|
GrafanaTable,
|
|
102
102
|
GrafanaTimeSeriesTarget,
|
|
103
|
+
Metric,
|
|
103
104
|
ModelEndpoint,
|
|
104
105
|
ModelEndpointList,
|
|
105
106
|
ModelEndpointMetadata,
|
|
106
107
|
ModelEndpointSpec,
|
|
107
108
|
ModelEndpointStatus,
|
|
109
|
+
ModelMonitoringMode,
|
|
108
110
|
ModelMonitoringStoreKinds,
|
|
109
111
|
)
|
|
110
112
|
from .object import ObjectKind, ObjectMetadata, ObjectSpec, ObjectStatus
|
mlrun/api/schemas/constants.py
CHANGED
|
@@ -170,19 +170,6 @@ class APIStates:
|
|
|
170
170
|
def terminal_states():
|
|
171
171
|
return [APIStates.online, APIStates.offline]
|
|
172
172
|
|
|
173
|
-
@staticmethod
|
|
174
|
-
def description(state: str):
|
|
175
|
-
return {
|
|
176
|
-
APIStates.online: "API is online",
|
|
177
|
-
APIStates.waiting_for_migrations: "API is waiting for migrations to be triggered. "
|
|
178
|
-
"Send POST request to /api/operations/migrations to trigger it",
|
|
179
|
-
APIStates.migrations_in_progress: "Migrations are in progress",
|
|
180
|
-
APIStates.migrations_failed: "Migrations failed, API can't be started",
|
|
181
|
-
APIStates.migrations_completed: "Migrations completed, API is waiting to become online",
|
|
182
|
-
APIStates.offline: "API is offline",
|
|
183
|
-
APIStates.waiting_for_chief: "API is waiting for chief to be ready",
|
|
184
|
-
}.get(state, f"Unknown API state '{state}'")
|
|
185
|
-
|
|
186
173
|
|
|
187
174
|
class ClusterizationRole:
|
|
188
175
|
chief = "chief"
|
|
@@ -67,7 +67,6 @@ class FrontendSpec(pydantic.BaseModel):
|
|
|
67
67
|
default_function_pod_resources: Resources = Resources()
|
|
68
68
|
default_function_preemption_mode: str
|
|
69
69
|
feature_store_data_prefixes: typing.Optional[typing.Dict[str, str]]
|
|
70
|
-
allowed_artifact_path_prefixes_list: typing.List[str]
|
|
71
70
|
|
|
72
71
|
# ce_mode is deprecated, we will use the full ce config instead and ce_mode will be removed in 1.6.0
|
|
73
72
|
ce_mode: typing.Optional[str]
|