mlrun 1.7.2rc3__py3-none-any.whl → 1.8.0rc1__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 (222) hide show
  1. mlrun/__init__.py +14 -12
  2. mlrun/__main__.py +3 -3
  3. mlrun/alerts/alert.py +19 -12
  4. mlrun/artifacts/__init__.py +0 -2
  5. mlrun/artifacts/base.py +34 -11
  6. mlrun/artifacts/dataset.py +16 -16
  7. mlrun/artifacts/manager.py +13 -13
  8. mlrun/artifacts/model.py +66 -53
  9. mlrun/common/constants.py +6 -0
  10. mlrun/common/formatters/__init__.py +1 -0
  11. mlrun/common/formatters/feature_set.py +1 -0
  12. mlrun/common/formatters/function.py +1 -0
  13. mlrun/common/formatters/model_endpoint.py +30 -0
  14. mlrun/common/formatters/pipeline.py +1 -2
  15. mlrun/common/model_monitoring/__init__.py +0 -3
  16. mlrun/common/model_monitoring/helpers.py +1 -1
  17. mlrun/common/runtimes/constants.py +1 -2
  18. mlrun/common/schemas/__init__.py +4 -2
  19. mlrun/common/schemas/artifact.py +0 -6
  20. mlrun/common/schemas/common.py +50 -0
  21. mlrun/common/schemas/model_monitoring/__init__.py +8 -1
  22. mlrun/common/schemas/model_monitoring/constants.py +62 -12
  23. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +149 -0
  24. mlrun/common/schemas/model_monitoring/model_endpoints.py +21 -5
  25. mlrun/common/schemas/partition.py +122 -0
  26. mlrun/config.py +43 -15
  27. mlrun/data_types/__init__.py +0 -2
  28. mlrun/data_types/data_types.py +0 -1
  29. mlrun/data_types/infer.py +3 -1
  30. mlrun/data_types/spark.py +4 -4
  31. mlrun/data_types/to_pandas.py +2 -11
  32. mlrun/datastore/__init__.py +0 -2
  33. mlrun/datastore/alibaba_oss.py +4 -1
  34. mlrun/datastore/azure_blob.py +4 -1
  35. mlrun/datastore/base.py +12 -4
  36. mlrun/datastore/datastore.py +9 -3
  37. mlrun/datastore/datastore_profile.py +1 -1
  38. mlrun/datastore/dbfs_store.py +4 -1
  39. mlrun/datastore/filestore.py +4 -1
  40. mlrun/datastore/google_cloud_storage.py +4 -1
  41. mlrun/datastore/hdfs.py +4 -1
  42. mlrun/datastore/inmem.py +4 -1
  43. mlrun/datastore/redis.py +4 -1
  44. mlrun/datastore/s3.py +4 -1
  45. mlrun/datastore/sources.py +51 -49
  46. mlrun/datastore/store_resources.py +0 -2
  47. mlrun/datastore/targets.py +22 -23
  48. mlrun/datastore/utils.py +2 -2
  49. mlrun/datastore/v3io.py +4 -1
  50. mlrun/datastore/wasbfs/fs.py +13 -12
  51. mlrun/db/base.py +126 -62
  52. mlrun/db/factory.py +3 -0
  53. mlrun/db/httpdb.py +767 -231
  54. mlrun/db/nopdb.py +126 -57
  55. mlrun/errors.py +2 -2
  56. mlrun/execution.py +55 -29
  57. mlrun/feature_store/__init__.py +0 -2
  58. mlrun/feature_store/api.py +40 -40
  59. mlrun/feature_store/common.py +9 -9
  60. mlrun/feature_store/feature_set.py +20 -18
  61. mlrun/feature_store/feature_vector.py +27 -24
  62. mlrun/feature_store/retrieval/base.py +14 -9
  63. mlrun/feature_store/retrieval/job.py +2 -1
  64. mlrun/feature_store/steps.py +2 -2
  65. mlrun/features.py +30 -13
  66. mlrun/frameworks/__init__.py +1 -2
  67. mlrun/frameworks/_common/__init__.py +1 -2
  68. mlrun/frameworks/_common/artifacts_library.py +2 -2
  69. mlrun/frameworks/_common/mlrun_interface.py +10 -6
  70. mlrun/frameworks/_common/model_handler.py +29 -27
  71. mlrun/frameworks/_common/producer.py +3 -1
  72. mlrun/frameworks/_dl_common/__init__.py +1 -2
  73. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
  74. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
  75. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
  76. mlrun/frameworks/_ml_common/__init__.py +1 -2
  77. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
  78. mlrun/frameworks/_ml_common/model_handler.py +21 -21
  79. mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
  80. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
  81. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  82. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  83. mlrun/frameworks/auto_mlrun/__init__.py +1 -2
  84. mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
  85. mlrun/frameworks/huggingface/__init__.py +1 -2
  86. mlrun/frameworks/huggingface/model_server.py +9 -9
  87. mlrun/frameworks/lgbm/__init__.py +47 -44
  88. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
  89. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
  90. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
  91. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
  92. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
  93. mlrun/frameworks/lgbm/model_handler.py +15 -11
  94. mlrun/frameworks/lgbm/model_server.py +11 -7
  95. mlrun/frameworks/lgbm/utils.py +2 -2
  96. mlrun/frameworks/onnx/__init__.py +1 -2
  97. mlrun/frameworks/onnx/dataset.py +3 -3
  98. mlrun/frameworks/onnx/mlrun_interface.py +2 -2
  99. mlrun/frameworks/onnx/model_handler.py +7 -5
  100. mlrun/frameworks/onnx/model_server.py +8 -6
  101. mlrun/frameworks/parallel_coordinates.py +11 -11
  102. mlrun/frameworks/pytorch/__init__.py +22 -23
  103. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
  104. mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
  105. mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
  106. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
  107. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
  108. mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
  109. mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
  110. mlrun/frameworks/pytorch/model_handler.py +21 -17
  111. mlrun/frameworks/pytorch/model_server.py +13 -9
  112. mlrun/frameworks/sklearn/__init__.py +19 -18
  113. mlrun/frameworks/sklearn/estimator.py +2 -2
  114. mlrun/frameworks/sklearn/metric.py +3 -3
  115. mlrun/frameworks/sklearn/metrics_library.py +8 -6
  116. mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
  117. mlrun/frameworks/sklearn/model_handler.py +4 -3
  118. mlrun/frameworks/tf_keras/__init__.py +11 -12
  119. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
  120. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
  121. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
  122. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
  123. mlrun/frameworks/tf_keras/model_handler.py +17 -13
  124. mlrun/frameworks/tf_keras/model_server.py +12 -8
  125. mlrun/frameworks/xgboost/__init__.py +19 -18
  126. mlrun/frameworks/xgboost/model_handler.py +13 -9
  127. mlrun/launcher/base.py +3 -4
  128. mlrun/launcher/local.py +1 -1
  129. mlrun/launcher/remote.py +1 -1
  130. mlrun/lists.py +4 -3
  131. mlrun/model.py +108 -44
  132. mlrun/model_monitoring/__init__.py +1 -2
  133. mlrun/model_monitoring/api.py +6 -6
  134. mlrun/model_monitoring/applications/_application_steps.py +13 -15
  135. mlrun/model_monitoring/applications/histogram_data_drift.py +41 -15
  136. mlrun/model_monitoring/applications/results.py +55 -3
  137. mlrun/model_monitoring/controller.py +185 -223
  138. mlrun/model_monitoring/db/_schedules.py +156 -0
  139. mlrun/model_monitoring/db/_stats.py +189 -0
  140. mlrun/model_monitoring/db/stores/__init__.py +1 -1
  141. mlrun/model_monitoring/db/stores/base/store.py +6 -65
  142. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -25
  143. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -97
  144. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +2 -58
  145. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -15
  146. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +6 -257
  147. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +9 -271
  148. mlrun/model_monitoring/db/tsdb/base.py +74 -22
  149. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +66 -35
  150. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
  151. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +284 -51
  152. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
  153. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +35 -17
  154. mlrun/model_monitoring/helpers.py +97 -1
  155. mlrun/model_monitoring/model_endpoint.py +4 -2
  156. mlrun/model_monitoring/stream_processing.py +2 -2
  157. mlrun/model_monitoring/tracking_policy.py +10 -3
  158. mlrun/model_monitoring/writer.py +47 -26
  159. mlrun/package/__init__.py +3 -6
  160. mlrun/package/context_handler.py +1 -1
  161. mlrun/package/packager.py +12 -9
  162. mlrun/package/packagers/__init__.py +0 -2
  163. mlrun/package/packagers/default_packager.py +14 -11
  164. mlrun/package/packagers/numpy_packagers.py +16 -7
  165. mlrun/package/packagers/pandas_packagers.py +18 -18
  166. mlrun/package/packagers/python_standard_library_packagers.py +25 -11
  167. mlrun/package/packagers_manager.py +31 -14
  168. mlrun/package/utils/__init__.py +0 -3
  169. mlrun/package/utils/_pickler.py +6 -6
  170. mlrun/platforms/__init__.py +3 -3
  171. mlrun/platforms/iguazio.py +4 -1
  172. mlrun/projects/__init__.py +1 -6
  173. mlrun/projects/operations.py +27 -27
  174. mlrun/projects/pipelines.py +85 -215
  175. mlrun/projects/project.py +444 -158
  176. mlrun/run.py +9 -9
  177. mlrun/runtimes/__init__.py +1 -3
  178. mlrun/runtimes/base.py +13 -10
  179. mlrun/runtimes/daskjob.py +9 -9
  180. mlrun/runtimes/generators.py +2 -1
  181. mlrun/runtimes/kubejob.py +4 -5
  182. mlrun/runtimes/mpijob/__init__.py +0 -2
  183. mlrun/runtimes/mpijob/abstract.py +7 -6
  184. mlrun/runtimes/nuclio/api_gateway.py +7 -7
  185. mlrun/runtimes/nuclio/application/application.py +11 -11
  186. mlrun/runtimes/nuclio/function.py +14 -13
  187. mlrun/runtimes/nuclio/serving.py +9 -9
  188. mlrun/runtimes/pod.py +74 -29
  189. mlrun/runtimes/remotesparkjob.py +3 -2
  190. mlrun/runtimes/sparkjob/__init__.py +0 -2
  191. mlrun/runtimes/sparkjob/spark3job.py +21 -11
  192. mlrun/runtimes/utils.py +6 -5
  193. mlrun/serving/merger.py +6 -4
  194. mlrun/serving/remote.py +18 -17
  195. mlrun/serving/routers.py +27 -27
  196. mlrun/serving/server.py +1 -1
  197. mlrun/serving/states.py +76 -71
  198. mlrun/serving/utils.py +13 -2
  199. mlrun/serving/v1_serving.py +3 -2
  200. mlrun/serving/v2_serving.py +4 -4
  201. mlrun/track/__init__.py +1 -1
  202. mlrun/track/tracker.py +2 -2
  203. mlrun/track/trackers/mlflow_tracker.py +6 -5
  204. mlrun/utils/async_http.py +1 -1
  205. mlrun/utils/helpers.py +72 -28
  206. mlrun/utils/logger.py +104 -2
  207. mlrun/utils/notifications/notification/base.py +23 -4
  208. mlrun/utils/notifications/notification/console.py +1 -1
  209. mlrun/utils/notifications/notification/git.py +6 -6
  210. mlrun/utils/notifications/notification/ipython.py +5 -4
  211. mlrun/utils/notifications/notification/slack.py +1 -1
  212. mlrun/utils/notifications/notification/webhook.py +13 -17
  213. mlrun/utils/notifications/notification_pusher.py +23 -19
  214. mlrun/utils/regex.py +1 -1
  215. mlrun/utils/version/version.json +2 -2
  216. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc1.dist-info}/METADATA +186 -186
  217. mlrun-1.8.0rc1.dist-info/RECORD +356 -0
  218. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc1.dist-info}/WHEEL +1 -1
  219. mlrun-1.7.2rc3.dist-info/RECORD +0 -351
  220. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc1.dist-info}/LICENSE +0 -0
  221. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc1.dist-info}/entry_points.txt +0 -0
  222. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,156 @@
1
+ # Copyright 2024 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
+ from contextlib import AbstractContextManager
17
+ from types import TracebackType
18
+ from typing import Final, Optional
19
+
20
+ import botocore.exceptions
21
+
22
+ import mlrun.common.schemas
23
+ import mlrun.errors
24
+ import mlrun.model_monitoring.helpers
25
+ from mlrun.utils import logger
26
+
27
+
28
+ class ModelMonitoringSchedulesFile(AbstractContextManager):
29
+ DEFAULT_SCHEDULES: Final = {}
30
+ INITIAL_CONTENT = json.dumps(DEFAULT_SCHEDULES)
31
+ ENCODING = "utf-8"
32
+
33
+ def __init__(self, project: str, endpoint_id: str) -> None:
34
+ """
35
+ Initialize applications monitoring schedules file object.
36
+ The JSON file stores a dictionary of registered application name as key and Unix timestamp as value.
37
+ When working with the schedules data, use this class as a context manager to read and write the data.
38
+
39
+ :param project: The project name.
40
+ :param endpoint_id: The endpoint ID.
41
+ """
42
+ # `self._item` is the persistent version of the monitoring schedules.
43
+ self._item = mlrun.model_monitoring.helpers.get_monitoring_schedules_data(
44
+ project=project, endpoint_id=endpoint_id
45
+ )
46
+ self._path = self._item.url
47
+ self._fs = self._item.store.filesystem
48
+ # `self._schedules` is an in-memory copy of the DB for all the applications for
49
+ # the same model endpoint.
50
+ self._schedules: dict[str, int] = self.DEFAULT_SCHEDULES.copy()
51
+ # Does `self._schedules` hold the content of `self._item`?
52
+ self._open_schedules = False
53
+
54
+ @classmethod
55
+ def from_model_endpoint(
56
+ cls, model_endpoint: mlrun.common.schemas.ModelEndpoint
57
+ ) -> "ModelMonitoringSchedulesFile":
58
+ return cls(
59
+ project=model_endpoint.metadata.project,
60
+ endpoint_id=model_endpoint.metadata.uid,
61
+ )
62
+
63
+ def create(self) -> None:
64
+ """Create a schedules file with initial content - an empty dictionary"""
65
+ logger.debug("Creating model monitoring schedules file", path=self._item.url)
66
+ self._item.put(self.INITIAL_CONTENT)
67
+
68
+ def delete(self) -> None:
69
+ """Delete schedules file if it exists"""
70
+ if (
71
+ self._fs is None # In-memory store
72
+ or self._fs.exists(self._path)
73
+ ):
74
+ logger.debug(
75
+ "Deleting model monitoring schedules file", path=self._item.url
76
+ )
77
+ self._item.delete()
78
+ else:
79
+ logger.debug(
80
+ "Model monitoring schedules file does not exist, nothing to delete",
81
+ path=self._item.url,
82
+ )
83
+
84
+ def _open(self) -> None:
85
+ try:
86
+ content = self._item.get()
87
+ except (
88
+ mlrun.errors.MLRunNotFoundError,
89
+ # Different errors are raised for S3 or local storage, see ML-8042
90
+ botocore.exceptions.ClientError,
91
+ FileNotFoundError,
92
+ ) as err:
93
+ if (
94
+ isinstance(err, botocore.exceptions.ClientError)
95
+ # Add a log only to "NoSuchKey" errors codes - equivalent to `FileNotFoundError`
96
+ and err.response["Error"]["Code"] != "NoSuchKey"
97
+ ):
98
+ raise
99
+
100
+ logger.exception(
101
+ "The schedules file was not found. It should have been created "
102
+ "as a part of the model endpoint's creation",
103
+ path=self._path,
104
+ )
105
+ raise
106
+
107
+ if isinstance(content, bytes):
108
+ content = content.decode(encoding=self.ENCODING)
109
+ self._schedules = json.loads(content)
110
+ self._open_schedules = True
111
+
112
+ def _close(self) -> None:
113
+ self._item.put(json.dumps(self._schedules))
114
+ self._schedules = self.DEFAULT_SCHEDULES
115
+ self._open_schedules = False
116
+
117
+ def __enter__(self) -> "ModelMonitoringSchedulesFile":
118
+ self._open()
119
+ return super().__enter__()
120
+
121
+ def __exit__(
122
+ self,
123
+ exc_type: Optional[type[BaseException]],
124
+ exc_value: Optional[BaseException],
125
+ traceback: Optional[TracebackType],
126
+ ) -> Optional[bool]:
127
+ self._close()
128
+
129
+ def _check_open_schedules(self) -> None:
130
+ if not self._open_schedules:
131
+ raise mlrun.errors.MLRunValueError(
132
+ "Open the schedules file as a context manager first"
133
+ )
134
+
135
+ def get_application_time(self, application: str) -> Optional[int]:
136
+ self._check_open_schedules()
137
+ return self._schedules.get(application)
138
+
139
+ def update_application_time(self, application: str, timestamp: int) -> None:
140
+ self._check_open_schedules()
141
+ self._schedules[application] = timestamp
142
+
143
+
144
+ def delete_model_monitoring_schedules_folder(project: str) -> None:
145
+ """Delete the model monitoring schedules folder of the project"""
146
+ folder = mlrun.model_monitoring.helpers._get_monitoring_schedules_folder_path(
147
+ project
148
+ )
149
+ fs = mlrun.datastore.store_manager.object(folder).store.filesystem
150
+ if fs and fs.exists(folder):
151
+ logger.debug("Deleting model monitoring schedules folder", folder=folder)
152
+ fs.rm(folder, recursive=True)
153
+ elif fs is None: # In-memory store
154
+ raise mlrun.errors.MLRunValueError(
155
+ "Cannot delete a folder without a file-system"
156
+ )
@@ -0,0 +1,189 @@
1
+ # Copyright 2024 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
+ import abc
15
+ import json
16
+ from abc import abstractmethod
17
+ from datetime import datetime, timezone
18
+ from typing import cast
19
+
20
+ import botocore.exceptions
21
+ import fsspec
22
+
23
+ import mlrun.datastore.base
24
+ from mlrun.common.schemas.model_monitoring.constants import StatsKind
25
+ from mlrun.model_monitoring.helpers import (
26
+ get_monitoring_current_stats_data,
27
+ get_monitoring_drift_measures_data,
28
+ get_monitoring_stats_directory_path,
29
+ )
30
+ from mlrun.utils import logger
31
+
32
+
33
+ class ModelMonitoringStatsFile(abc.ABC):
34
+ """
35
+ Abstract class
36
+ Initialize applications monitoring stats file object.
37
+ The JSON file stores a dictionary of registered application name as key and Unix timestamp as value.
38
+ When working with the schedules data, use this class as a context manager to read and write the data.
39
+ """
40
+
41
+ def __init__(self, item: mlrun.datastore.base.DataItem, file_type: str):
42
+ self._path = item.url
43
+ self._item = item
44
+ self._file_type = file_type
45
+ self._fs = cast(fsspec.AbstractFileSystem, self._item.store.filesystem)
46
+
47
+ def create(self) -> None:
48
+ """Create a json file with initial content - an empty dictionary"""
49
+ logger.debug(
50
+ f"Creating model monitoring {self._file_type} file", path=self._item.url
51
+ )
52
+ self._item.put(
53
+ json.dumps(
54
+ {
55
+ "data": dict(),
56
+ "timestamp": mlrun.utils.datetime_now().isoformat(
57
+ sep=" ", timespec="microseconds"
58
+ ),
59
+ }
60
+ )
61
+ )
62
+
63
+ def delete(self) -> None:
64
+ """Delete json file if it exists"""
65
+ if self._fs.exists(self._path):
66
+ logger.debug(
67
+ f"Deleting model monitoring {self._file_type} file", path=self._item.url
68
+ )
69
+ self._item.delete()
70
+ else:
71
+ logger.debug(
72
+ f"Model monitoring {self._file_type} file does not exist, nothing to delete",
73
+ path=self._item.url,
74
+ )
75
+
76
+ def read(self) -> tuple[dict, datetime]:
77
+ """
78
+ Read the stats data and timestamp saved in file
79
+ :return: tuple[dict, str] dictionary with stats data and timestamp saved in file
80
+ """
81
+ try:
82
+ content = json.loads(self._item.get().decode())
83
+ timestamp = content.get("timestamp")
84
+ if timestamp is not None:
85
+ timestamp = datetime.fromisoformat(timestamp).astimezone(
86
+ tz=timezone.utc
87
+ )
88
+ return content.get("data"), timestamp
89
+ except (
90
+ mlrun.errors.MLRunNotFoundError,
91
+ # Different errors are raised for S3 or local storage, see ML-8042
92
+ botocore.exceptions.ClientError,
93
+ FileNotFoundError,
94
+ ) as err:
95
+ if (
96
+ isinstance(err, botocore.exceptions.ClientError)
97
+ # Add a log only to "NoSuchKey" errors codes - equivalent to `FileNotFoundError`
98
+ and err.response["Error"]["Code"] != "NoSuchKey"
99
+ ):
100
+ raise
101
+
102
+ logger.exception(
103
+ "The Stats file was not found. It should have been created "
104
+ "as a part of the model endpoint's creation",
105
+ path=self._path,
106
+ error=err,
107
+ )
108
+ raise
109
+
110
+ def write(self, stats: dict, timestamp: datetime) -> None:
111
+ """
112
+ Write stats data to file overwrite the existing file
113
+ :param stats: dictionary with the stats data
114
+ :param timestamp: datetime object with the timestamp of last entry point for the stats calculation
115
+ """
116
+ content = {
117
+ "data": stats,
118
+ "timestamp": timestamp.isoformat(sep=" ", timespec="microseconds"),
119
+ }
120
+ self._item.put(json.dumps(content))
121
+
122
+ @classmethod
123
+ @abstractmethod
124
+ def from_model_endpoint(
125
+ cls, model_endpoint: mlrun.common.schemas.ModelEndpoint
126
+ ) -> "ModelMonitoringStatsFile":
127
+ """
128
+ Return ModelMonitoringStatsFile child object using ModelEndpoint metadata
129
+ :param model_endpoint: The current model endpoint to get a stats object for
130
+ :return: ModelMonitoringStatsFile child object instance
131
+ """
132
+ pass
133
+
134
+
135
+ class ModelMonitoringCurrentStatsFile(ModelMonitoringStatsFile):
136
+ def __init__(self, project: str, endpoint_id: str) -> None:
137
+ """
138
+ Initialize File object specific for current stats.
139
+ :param project: (str) Project name
140
+ :param endpoint_id: (str) Endpoint name
141
+ """
142
+ super().__init__(
143
+ get_monitoring_current_stats_data(project, endpoint_id),
144
+ StatsKind.CURRENT_STATS.value,
145
+ )
146
+
147
+ @classmethod
148
+ def from_model_endpoint(
149
+ cls, model_endpoint: mlrun.common.schemas.ModelEndpoint
150
+ ) -> "ModelMonitoringCurrentStatsFile":
151
+ return cls(
152
+ project=model_endpoint.metadata.project,
153
+ endpoint_id=model_endpoint.metadata.uid,
154
+ )
155
+
156
+
157
+ class ModelMonitoringDriftMeasuresFile(ModelMonitoringStatsFile):
158
+ def __init__(self, project: str, endpoint_id: str) -> None:
159
+ """
160
+ Initialize File object specific for drift measures.
161
+ :param project: (str) Project name
162
+ :param endpoint_id: (str) Endpoint name
163
+ """
164
+ super().__init__(
165
+ get_monitoring_drift_measures_data(project, endpoint_id),
166
+ StatsKind.DRIFT_MEASURES.value,
167
+ )
168
+
169
+ @classmethod
170
+ def from_model_endpoint(
171
+ cls, model_endpoint: mlrun.common.schemas.ModelEndpoint
172
+ ) -> "ModelMonitoringDriftMeasuresFile":
173
+ return cls(
174
+ project=model_endpoint.metadata.project,
175
+ endpoint_id=model_endpoint.metadata.uid,
176
+ )
177
+
178
+
179
+ def delete_model_monitoring_stats_folder(project: str) -> None:
180
+ """Delete the model monitoring schedules folder of the project"""
181
+ folder = get_monitoring_stats_directory_path(project)
182
+ fs = mlrun.datastore.store_manager.object(folder).store.filesystem
183
+ if fs and fs.exists(folder):
184
+ logger.debug("Deleting model monitoring stats folder", folder=folder)
185
+ fs.rm(folder, recursive=True)
186
+ elif fs is None: # In-memory store
187
+ raise mlrun.errors.MLRunValueError(
188
+ "Cannot delete a folder without a file-system"
189
+ )
@@ -70,7 +70,7 @@ class ObjectStoreFactory(enum.Enum):
70
70
 
71
71
  def get_model_endpoint_store(
72
72
  project: str,
73
- access_key: str = None,
73
+ access_key: typing.Optional[str] = None,
74
74
  secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
75
75
  ) -> StoreBase:
76
76
  # Leaving here for backwards compatibility
@@ -90,12 +90,12 @@ class StoreBase(ABC):
90
90
  @abstractmethod
91
91
  def list_model_endpoints(
92
92
  self,
93
- model: str = None,
94
- function: str = None,
95
- labels: list[str] = None,
96
- top_level: bool = None,
97
- uids: list = None,
98
- include_stats: bool = None,
93
+ model: typing.Optional[str] = None,
94
+ function: typing.Optional[str] = None,
95
+ labels: typing.Optional[list[str]] = None,
96
+ top_level: typing.Optional[bool] = None,
97
+ uids: typing.Optional[list] = None,
98
+ include_stats: typing.Optional[bool] = None,
99
99
  ) -> list[dict[str, typing.Any]]:
100
100
  """
101
101
  Returns a list of model endpoint dictionaries, supports filtering by model, function, labels or top level.
@@ -115,65 +115,6 @@ class StoreBase(ABC):
115
115
  """
116
116
  pass
117
117
 
118
- @abstractmethod
119
- def write_application_event(
120
- self,
121
- event: dict[str, typing.Any],
122
- kind: mm_schemas.WriterEventKind = mm_schemas.WriterEventKind.RESULT,
123
- ) -> None:
124
- """
125
- Write a new event in the target table.
126
-
127
- :param event: An event dictionary that represents the application result, should be corresponded to the
128
- schema defined in the :py:class:`~mlrun.common.schemas.model_monitoring.constants.WriterEvent`
129
- object.
130
- :param kind: The type of the event, can be either "result" or "metric".
131
- """
132
-
133
- @abstractmethod
134
- def get_last_analyzed(self, endpoint_id: str, application_name: str) -> int:
135
- """
136
- Get the last analyzed time for the provided model endpoint and application.
137
-
138
- :param endpoint_id: The unique id of the model endpoint.
139
- :param application_name: Registered application name.
140
-
141
- :return: Timestamp as a Unix time.
142
- :raise: MLRunNotFoundError if last analyzed value is not found.
143
- """
144
- pass
145
-
146
- @abstractmethod
147
- def update_last_analyzed(
148
- self,
149
- endpoint_id: str,
150
- application_name: str,
151
- last_analyzed: int,
152
- ):
153
- """
154
- Update the last analyzed time for the provided model endpoint and application.
155
-
156
- :param endpoint_id: The unique id of the model endpoint.
157
- :param application_name: Registered application name.
158
- :param last_analyzed: Timestamp as a Unix time that represents the last analyzed time of a certain
159
- application and model endpoint.
160
-
161
- """
162
- pass
163
-
164
- @abstractmethod
165
- def get_model_endpoint_metrics(
166
- self, endpoint_id: str, type: mm_schemas.ModelEndpointMonitoringMetricType
167
- ) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
168
- """
169
- Get the model monitoring results and metrics of the requested model endpoint.
170
-
171
- :param: endpoint_id: The model endpoint identifier.
172
- :param: type: The type of the requested metrics ("result" or "metric").
173
-
174
- :return: A list of the available metrics.
175
- """
176
-
177
118
  @staticmethod
178
119
  def _validate_labels(
179
120
  endpoint_dict: dict,
@@ -15,14 +15,8 @@
15
15
  from functools import partial
16
16
  from typing import Optional, TypeVar, Union
17
17
 
18
- from .mysql import ApplicationMetricsTable as MySQLApplicationMetricsTable
19
- from .mysql import ApplicationResultTable as MySQLApplicationResultTable
20
18
  from .mysql import ModelEndpointsTable as MySQLModelEndpointsTable
21
- from .mysql import MonitoringSchedulesTable as MySQLMonitoringSchedulesTable
22
- from .sqlite import ApplicationMetricsTable as SQLiteApplicationMetricsTable
23
- from .sqlite import ApplicationResultTable as SQLiteApplicationResultTable
24
19
  from .sqlite import ModelEndpointsTable as SQLiteModelEndpointsTable
25
- from .sqlite import MonitoringSchedulesTable as SQLiteMonitoringSchedulesTable
26
20
 
27
21
  MySQLTableType = TypeVar("MySQLTableType")
28
22
  SQLiteTableType = TypeVar("SQLiteTableType")
@@ -50,22 +44,3 @@ _get_model_endpoints_table = partial(
50
44
  mysql_table=MySQLModelEndpointsTable,
51
45
  sqlite_table=SQLiteModelEndpointsTable,
52
46
  )
53
-
54
-
55
- _get_application_result_table = partial(
56
- _get_sql_table,
57
- mysql_table=MySQLApplicationResultTable,
58
- sqlite_table=SQLiteApplicationResultTable,
59
- )
60
-
61
- _get_application_metrics_table = partial(
62
- _get_sql_table,
63
- mysql_table=MySQLApplicationMetricsTable,
64
- sqlite_table=SQLiteApplicationMetricsTable,
65
- )
66
-
67
- _get_monitoring_schedules_table = partial(
68
- _get_sql_table,
69
- mysql_table=MySQLMonitoringSchedulesTable,
70
- sqlite_table=SQLiteMonitoringSchedulesTable,
71
- )
@@ -13,11 +13,9 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from sqlalchemy import (
16
- DATETIME,
17
16
  TIMESTAMP, # TODO: migrate to DATETIME, see ML-6921
18
17
  Boolean,
19
18
  Column,
20
- Float,
21
19
  Integer,
22
20
  String,
23
21
  Text,
@@ -25,11 +23,6 @@ from sqlalchemy import (
25
23
 
26
24
  from mlrun.common.schemas.model_monitoring import (
27
25
  EventFieldType,
28
- FileTargetKind,
29
- MetricData,
30
- ResultData,
31
- SchedulingKeys,
32
- WriterEvent,
33
26
  )
34
27
  from mlrun.utils.db import BaseModel
35
28
 
@@ -98,93 +91,3 @@ class ModelEndpointsBaseTable(BaseModel):
98
91
  EventFieldType.LAST_REQUEST,
99
92
  TIMESTAMP(timezone=True), # TODO: migrate to DATETIME, see ML-6921
100
93
  )
101
-
102
-
103
- class ApplicationResultBaseTable(BaseModel):
104
- __tablename__ = FileTargetKind.APP_RESULTS
105
-
106
- uid = Column(EventFieldType.UID, String(120), primary_key=True)
107
-
108
- application_name = Column(
109
- WriterEvent.APPLICATION_NAME,
110
- String(40),
111
- nullable=True,
112
- )
113
-
114
- endpoint_id = Column(
115
- WriterEvent.ENDPOINT_ID,
116
- String(40),
117
- nullable=True,
118
- )
119
-
120
- result_name = Column(
121
- ResultData.RESULT_NAME,
122
- String(40),
123
- )
124
-
125
- start_infer_time = Column(
126
- WriterEvent.START_INFER_TIME,
127
- DATETIME(timezone=True),
128
- )
129
- end_infer_time = Column(
130
- WriterEvent.END_INFER_TIME,
131
- DATETIME(timezone=True),
132
- )
133
-
134
- result_status = Column(ResultData.RESULT_STATUS, String(10))
135
- result_kind = Column(ResultData.RESULT_KIND, String(40))
136
- result_value = Column(ResultData.RESULT_VALUE, Float)
137
- result_extra_data = Column(ResultData.RESULT_EXTRA_DATA, Text)
138
- current_stats = Column(ResultData.CURRENT_STATS, Text)
139
-
140
-
141
- class ApplicationMetricsBaseTable(BaseModel):
142
- __tablename__ = FileTargetKind.APP_METRICS
143
-
144
- uid = Column(EventFieldType.UID, String(120), primary_key=True)
145
- application_name = Column(
146
- WriterEvent.APPLICATION_NAME,
147
- String(40),
148
- nullable=True,
149
- )
150
- endpoint_id = Column(
151
- WriterEvent.ENDPOINT_ID,
152
- String(40),
153
- nullable=True,
154
- )
155
- start_infer_time = Column(
156
- WriterEvent.START_INFER_TIME,
157
- DATETIME(timezone=True),
158
- )
159
- end_infer_time = Column(
160
- WriterEvent.END_INFER_TIME,
161
- DATETIME(timezone=True),
162
- )
163
- metric_name = Column(
164
- MetricData.METRIC_NAME,
165
- String(40),
166
- )
167
- metric_value = Column(MetricData.METRIC_VALUE, Float)
168
-
169
-
170
- class MonitoringSchedulesBaseTable(BaseModel):
171
- __tablename__ = FileTargetKind.MONITORING_SCHEDULES
172
-
173
- uid = Column(SchedulingKeys.UID, String(32), primary_key=True)
174
-
175
- application_name = Column(
176
- SchedulingKeys.APPLICATION_NAME,
177
- String(40),
178
- nullable=False,
179
- )
180
-
181
- endpoint_id = Column(
182
- SchedulingKeys.ENDPOINT_ID,
183
- String(40),
184
- nullable=False,
185
- )
186
-
187
- last_analyzed = Column(
188
- SchedulingKeys.LAST_ANALYZED,
189
- Integer,
190
- )
@@ -13,20 +13,15 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import sqlalchemy.dialects.mysql
16
- from sqlalchemy import Column, ForeignKey, String
17
- from sqlalchemy.ext.declarative import declarative_base, declared_attr
16
+ from sqlalchemy import Column
17
+ from sqlalchemy.ext.declarative import declarative_base
18
18
 
19
19
  from mlrun.common.schemas.model_monitoring import (
20
20
  EventFieldType,
21
- ResultData,
22
- WriterEvent,
23
21
  )
24
22
 
25
23
  from .base import (
26
- ApplicationMetricsBaseTable,
27
- ApplicationResultBaseTable,
28
24
  ModelEndpointsBaseTable,
29
- MonitoringSchedulesBaseTable,
30
25
  )
31
26
 
32
27
  Base = declarative_base()
@@ -50,54 +45,3 @@ class ModelEndpointsTable(Base, ModelEndpointsBaseTable):
50
45
  # TODO: migrate to DATETIME, see ML-6921
51
46
  sqlalchemy.dialects.mysql.TIMESTAMP(fsp=3, timezone=True),
52
47
  )
53
-
54
-
55
- class _ApplicationResultOrMetric:
56
- """
57
- This class sets common columns of `ApplicationResultTable` and `ApplicationMetricsTable`
58
- to the correct values in MySQL.
59
- Note: This class must come before the base tables in the inheritance order to override
60
- the relevant columns.
61
- """
62
-
63
- start_infer_time = Column(
64
- WriterEvent.START_INFER_TIME,
65
- sqlalchemy.dialects.mysql.DATETIME(fsp=3, timezone=True),
66
- )
67
- end_infer_time = Column(
68
- WriterEvent.END_INFER_TIME,
69
- sqlalchemy.dialects.mysql.DATETIME(fsp=3, timezone=True),
70
- )
71
-
72
- @declared_attr
73
- def endpoint_id(self):
74
- return Column(
75
- String(40),
76
- ForeignKey(f"{EventFieldType.MODEL_ENDPOINTS}.{EventFieldType.UID}"),
77
- )
78
-
79
-
80
- class ApplicationResultTable(
81
- Base, _ApplicationResultOrMetric, ApplicationResultBaseTable
82
- ):
83
- result_extra_data = Column(
84
- ResultData.RESULT_EXTRA_DATA, sqlalchemy.dialects.mysql.MEDIUMTEXT
85
- )
86
- current_stats = Column(
87
- ResultData.CURRENT_STATS, sqlalchemy.dialects.mysql.MEDIUMTEXT
88
- )
89
-
90
-
91
- class ApplicationMetricsTable(
92
- Base, _ApplicationResultOrMetric, ApplicationMetricsBaseTable
93
- ):
94
- pass
95
-
96
-
97
- class MonitoringSchedulesTable(Base, MonitoringSchedulesBaseTable):
98
- @declared_attr
99
- def endpoint_id(self):
100
- return Column(
101
- String(40),
102
- ForeignKey(f"{EventFieldType.MODEL_ENDPOINTS}.{EventFieldType.UID}"),
103
- )
@@ -15,10 +15,7 @@
15
15
  from sqlalchemy.ext.declarative import declarative_base
16
16
 
17
17
  from .base import (
18
- ApplicationMetricsBaseTable,
19
- ApplicationResultBaseTable,
20
18
  ModelEndpointsBaseTable,
21
- MonitoringSchedulesBaseTable,
22
19
  )
23
20
 
24
21
  Base = declarative_base()
@@ -26,15 +23,3 @@ Base = declarative_base()
26
23
 
27
24
  class ModelEndpointsTable(Base, ModelEndpointsBaseTable):
28
25
  pass
29
-
30
-
31
- class ApplicationResultTable(Base, ApplicationResultBaseTable):
32
- pass
33
-
34
-
35
- class ApplicationMetricsTable(Base, ApplicationMetricsBaseTable):
36
- pass
37
-
38
-
39
- class MonitoringSchedulesTable(Base, MonitoringSchedulesBaseTable):
40
- pass