mlrun 1.7.2rc3__py3-none-any.whl → 1.8.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 (250) hide show
  1. mlrun/__init__.py +18 -18
  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/formatters/project.py +9 -0
  16. mlrun/common/model_monitoring/__init__.py +0 -3
  17. mlrun/common/model_monitoring/helpers.py +1 -1
  18. mlrun/common/runtimes/constants.py +1 -2
  19. mlrun/common/schemas/__init__.py +7 -2
  20. mlrun/common/schemas/alert.py +31 -18
  21. mlrun/common/schemas/api_gateway.py +3 -3
  22. mlrun/common/schemas/artifact.py +7 -13
  23. mlrun/common/schemas/auth.py +6 -4
  24. mlrun/common/schemas/background_task.py +7 -7
  25. mlrun/common/schemas/client_spec.py +2 -2
  26. mlrun/common/schemas/clusterization_spec.py +2 -2
  27. mlrun/common/schemas/common.py +53 -3
  28. mlrun/common/schemas/datastore_profile.py +1 -1
  29. mlrun/common/schemas/feature_store.py +9 -9
  30. mlrun/common/schemas/frontend_spec.py +4 -4
  31. mlrun/common/schemas/function.py +10 -10
  32. mlrun/common/schemas/hub.py +1 -1
  33. mlrun/common/schemas/k8s.py +3 -3
  34. mlrun/common/schemas/memory_reports.py +3 -3
  35. mlrun/common/schemas/model_monitoring/__init__.py +8 -1
  36. mlrun/common/schemas/model_monitoring/constants.py +62 -12
  37. mlrun/common/schemas/model_monitoring/grafana.py +1 -1
  38. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +149 -0
  39. mlrun/common/schemas/model_monitoring/model_endpoints.py +22 -6
  40. mlrun/common/schemas/notification.py +18 -3
  41. mlrun/common/schemas/object.py +1 -1
  42. mlrun/common/schemas/pagination.py +4 -4
  43. mlrun/common/schemas/partition.py +137 -0
  44. mlrun/common/schemas/pipeline.py +2 -2
  45. mlrun/common/schemas/project.py +22 -17
  46. mlrun/common/schemas/runs.py +2 -2
  47. mlrun/common/schemas/runtime_resource.py +5 -5
  48. mlrun/common/schemas/schedule.py +1 -1
  49. mlrun/common/schemas/secret.py +1 -1
  50. mlrun/common/schemas/tag.py +3 -3
  51. mlrun/common/schemas/workflow.py +5 -5
  52. mlrun/config.py +65 -15
  53. mlrun/data_types/__init__.py +0 -2
  54. mlrun/data_types/data_types.py +0 -1
  55. mlrun/data_types/infer.py +3 -1
  56. mlrun/data_types/spark.py +4 -4
  57. mlrun/data_types/to_pandas.py +2 -11
  58. mlrun/datastore/__init__.py +0 -2
  59. mlrun/datastore/alibaba_oss.py +4 -1
  60. mlrun/datastore/azure_blob.py +4 -1
  61. mlrun/datastore/base.py +12 -4
  62. mlrun/datastore/datastore.py +9 -3
  63. mlrun/datastore/datastore_profile.py +20 -20
  64. mlrun/datastore/dbfs_store.py +4 -1
  65. mlrun/datastore/filestore.py +4 -1
  66. mlrun/datastore/google_cloud_storage.py +4 -1
  67. mlrun/datastore/hdfs.py +4 -1
  68. mlrun/datastore/inmem.py +4 -1
  69. mlrun/datastore/redis.py +4 -1
  70. mlrun/datastore/s3.py +4 -1
  71. mlrun/datastore/sources.py +51 -49
  72. mlrun/datastore/store_resources.py +0 -2
  73. mlrun/datastore/targets.py +22 -23
  74. mlrun/datastore/utils.py +2 -2
  75. mlrun/datastore/v3io.py +4 -1
  76. mlrun/datastore/wasbfs/fs.py +13 -12
  77. mlrun/db/base.py +170 -64
  78. mlrun/db/factory.py +3 -0
  79. mlrun/db/httpdb.py +986 -238
  80. mlrun/db/nopdb.py +155 -57
  81. mlrun/errors.py +2 -2
  82. mlrun/execution.py +55 -29
  83. mlrun/feature_store/__init__.py +0 -2
  84. mlrun/feature_store/api.py +40 -40
  85. mlrun/feature_store/common.py +9 -9
  86. mlrun/feature_store/feature_set.py +20 -18
  87. mlrun/feature_store/feature_vector.py +27 -24
  88. mlrun/feature_store/retrieval/base.py +14 -9
  89. mlrun/feature_store/retrieval/job.py +2 -1
  90. mlrun/feature_store/steps.py +2 -2
  91. mlrun/features.py +30 -13
  92. mlrun/frameworks/__init__.py +1 -2
  93. mlrun/frameworks/_common/__init__.py +1 -2
  94. mlrun/frameworks/_common/artifacts_library.py +2 -2
  95. mlrun/frameworks/_common/mlrun_interface.py +10 -6
  96. mlrun/frameworks/_common/model_handler.py +29 -27
  97. mlrun/frameworks/_common/producer.py +3 -1
  98. mlrun/frameworks/_dl_common/__init__.py +1 -2
  99. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
  100. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
  101. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
  102. mlrun/frameworks/_ml_common/__init__.py +1 -2
  103. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
  104. mlrun/frameworks/_ml_common/model_handler.py +21 -21
  105. mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
  106. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
  107. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  108. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  109. mlrun/frameworks/auto_mlrun/__init__.py +1 -2
  110. mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
  111. mlrun/frameworks/huggingface/__init__.py +1 -2
  112. mlrun/frameworks/huggingface/model_server.py +9 -9
  113. mlrun/frameworks/lgbm/__init__.py +47 -44
  114. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
  115. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
  116. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
  117. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
  118. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
  119. mlrun/frameworks/lgbm/model_handler.py +15 -11
  120. mlrun/frameworks/lgbm/model_server.py +11 -7
  121. mlrun/frameworks/lgbm/utils.py +2 -2
  122. mlrun/frameworks/onnx/__init__.py +1 -2
  123. mlrun/frameworks/onnx/dataset.py +3 -3
  124. mlrun/frameworks/onnx/mlrun_interface.py +2 -2
  125. mlrun/frameworks/onnx/model_handler.py +7 -5
  126. mlrun/frameworks/onnx/model_server.py +8 -6
  127. mlrun/frameworks/parallel_coordinates.py +11 -11
  128. mlrun/frameworks/pytorch/__init__.py +22 -23
  129. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
  130. mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
  131. mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
  132. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
  133. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
  134. mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
  135. mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
  136. mlrun/frameworks/pytorch/model_handler.py +21 -17
  137. mlrun/frameworks/pytorch/model_server.py +13 -9
  138. mlrun/frameworks/sklearn/__init__.py +19 -18
  139. mlrun/frameworks/sklearn/estimator.py +2 -2
  140. mlrun/frameworks/sklearn/metric.py +3 -3
  141. mlrun/frameworks/sklearn/metrics_library.py +8 -6
  142. mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
  143. mlrun/frameworks/sklearn/model_handler.py +4 -3
  144. mlrun/frameworks/tf_keras/__init__.py +11 -12
  145. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
  146. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
  147. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
  148. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
  149. mlrun/frameworks/tf_keras/model_handler.py +17 -13
  150. mlrun/frameworks/tf_keras/model_server.py +12 -8
  151. mlrun/frameworks/xgboost/__init__.py +19 -18
  152. mlrun/frameworks/xgboost/model_handler.py +13 -9
  153. mlrun/launcher/base.py +3 -4
  154. mlrun/launcher/local.py +1 -1
  155. mlrun/launcher/remote.py +1 -1
  156. mlrun/lists.py +4 -3
  157. mlrun/model.py +110 -46
  158. mlrun/model_monitoring/__init__.py +1 -2
  159. mlrun/model_monitoring/api.py +6 -6
  160. mlrun/model_monitoring/applications/_application_steps.py +13 -15
  161. mlrun/model_monitoring/applications/histogram_data_drift.py +41 -15
  162. mlrun/model_monitoring/applications/results.py +55 -3
  163. mlrun/model_monitoring/controller.py +185 -223
  164. mlrun/model_monitoring/db/_schedules.py +156 -0
  165. mlrun/model_monitoring/db/_stats.py +189 -0
  166. mlrun/model_monitoring/db/stores/__init__.py +1 -1
  167. mlrun/model_monitoring/db/stores/base/store.py +6 -65
  168. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -25
  169. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -97
  170. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +2 -58
  171. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -15
  172. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +6 -257
  173. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +9 -271
  174. mlrun/model_monitoring/db/tsdb/base.py +76 -24
  175. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +61 -6
  176. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
  177. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +253 -28
  178. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
  179. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +35 -17
  180. mlrun/model_monitoring/helpers.py +91 -1
  181. mlrun/model_monitoring/model_endpoint.py +4 -2
  182. mlrun/model_monitoring/stream_processing.py +16 -13
  183. mlrun/model_monitoring/tracking_policy.py +10 -3
  184. mlrun/model_monitoring/writer.py +47 -26
  185. mlrun/package/__init__.py +3 -6
  186. mlrun/package/context_handler.py +1 -1
  187. mlrun/package/packager.py +12 -9
  188. mlrun/package/packagers/__init__.py +0 -2
  189. mlrun/package/packagers/default_packager.py +14 -11
  190. mlrun/package/packagers/numpy_packagers.py +16 -7
  191. mlrun/package/packagers/pandas_packagers.py +18 -18
  192. mlrun/package/packagers/python_standard_library_packagers.py +25 -11
  193. mlrun/package/packagers_manager.py +31 -14
  194. mlrun/package/utils/__init__.py +0 -3
  195. mlrun/package/utils/_pickler.py +6 -6
  196. mlrun/platforms/__init__.py +3 -16
  197. mlrun/platforms/iguazio.py +4 -1
  198. mlrun/projects/operations.py +27 -27
  199. mlrun/projects/pipelines.py +34 -35
  200. mlrun/projects/project.py +535 -182
  201. mlrun/run.py +13 -10
  202. mlrun/runtimes/__init__.py +1 -3
  203. mlrun/runtimes/base.py +15 -11
  204. mlrun/runtimes/daskjob.py +9 -9
  205. mlrun/runtimes/generators.py +2 -1
  206. mlrun/runtimes/kubejob.py +4 -5
  207. mlrun/runtimes/mounts.py +572 -0
  208. mlrun/runtimes/mpijob/__init__.py +0 -2
  209. mlrun/runtimes/mpijob/abstract.py +7 -6
  210. mlrun/runtimes/nuclio/api_gateway.py +7 -7
  211. mlrun/runtimes/nuclio/application/application.py +11 -11
  212. mlrun/runtimes/nuclio/function.py +13 -13
  213. mlrun/runtimes/nuclio/serving.py +9 -9
  214. mlrun/runtimes/pod.py +154 -45
  215. mlrun/runtimes/remotesparkjob.py +3 -2
  216. mlrun/runtimes/sparkjob/__init__.py +0 -2
  217. mlrun/runtimes/sparkjob/spark3job.py +21 -11
  218. mlrun/runtimes/utils.py +6 -5
  219. mlrun/serving/merger.py +6 -4
  220. mlrun/serving/remote.py +18 -17
  221. mlrun/serving/routers.py +27 -27
  222. mlrun/serving/server.py +1 -1
  223. mlrun/serving/states.py +76 -71
  224. mlrun/serving/utils.py +13 -2
  225. mlrun/serving/v1_serving.py +3 -2
  226. mlrun/serving/v2_serving.py +4 -4
  227. mlrun/track/__init__.py +1 -1
  228. mlrun/track/tracker.py +2 -2
  229. mlrun/track/trackers/mlflow_tracker.py +6 -5
  230. mlrun/utils/async_http.py +1 -1
  231. mlrun/utils/helpers.py +70 -16
  232. mlrun/utils/logger.py +106 -4
  233. mlrun/utils/notifications/notification/__init__.py +22 -19
  234. mlrun/utils/notifications/notification/base.py +33 -14
  235. mlrun/utils/notifications/notification/console.py +6 -6
  236. mlrun/utils/notifications/notification/git.py +11 -11
  237. mlrun/utils/notifications/notification/ipython.py +10 -9
  238. mlrun/utils/notifications/notification/mail.py +149 -0
  239. mlrun/utils/notifications/notification/slack.py +6 -6
  240. mlrun/utils/notifications/notification/webhook.py +18 -22
  241. mlrun/utils/notifications/notification_pusher.py +43 -31
  242. mlrun/utils/regex.py +3 -1
  243. mlrun/utils/version/version.json +2 -2
  244. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc2.dist-info}/METADATA +18 -14
  245. mlrun-1.8.0rc2.dist-info/RECORD +358 -0
  246. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc2.dist-info}/WHEEL +1 -1
  247. mlrun-1.7.2rc3.dist-info/RECORD +0 -351
  248. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc2.dist-info}/LICENSE +0 -0
  249. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc2.dist-info}/entry_points.txt +0 -0
  250. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0rc2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,149 @@
1
+ # Copyright 2023 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 re
15
+ import typing
16
+ from email.message import EmailMessage
17
+
18
+ import aiosmtplib
19
+
20
+ import mlrun.common.schemas
21
+ import mlrun.lists
22
+ import mlrun.utils.helpers
23
+ import mlrun.utils.notifications.notification.base as base
24
+ import mlrun.utils.regex
25
+
26
+ DEFAULT_SMTP_PORT = 587
27
+
28
+
29
+ class MailNotification(base.NotificationBase):
30
+ """
31
+ API/Client notification for sending run statuses as a mail message
32
+ """
33
+
34
+ boolean_params = ["use_tls", "start_tls", "validate_certs"]
35
+
36
+ required_params = [
37
+ "server_host",
38
+ "server_port",
39
+ "sender_address",
40
+ "username",
41
+ "password",
42
+ "email_addresses",
43
+ ] + boolean_params
44
+
45
+ @classmethod
46
+ def validate_params(cls, params):
47
+ for required_param in cls.required_params:
48
+ if required_param not in params:
49
+ raise ValueError(
50
+ f"Parameter '{required_param}' is required for MailNotification"
51
+ )
52
+
53
+ for boolean_param in cls.boolean_params:
54
+ if not isinstance(params.get(boolean_param, None), bool):
55
+ raise ValueError(
56
+ f"Parameter '{boolean_param}' must be a boolean for MailNotification"
57
+ )
58
+
59
+ cls._validate_emails(params)
60
+
61
+ async def push(
62
+ self,
63
+ message: str,
64
+ severity: typing.Optional[
65
+ typing.Union[mlrun.common.schemas.NotificationSeverity, str]
66
+ ] = mlrun.common.schemas.NotificationSeverity.INFO,
67
+ runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
68
+ custom_html: typing.Optional[typing.Optional[str]] = None,
69
+ alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
70
+ event_data: typing.Optional[mlrun.common.schemas.Event] = None,
71
+ ):
72
+ self.params.setdefault("subject", f"[{severity}] {message}")
73
+ self.params.setdefault("body", message)
74
+ await self._send_email(**self.params)
75
+
76
+ @classmethod
77
+ def enrich_default_params(
78
+ cls, params: dict, default_params: typing.Optional[dict] = None
79
+ ) -> dict:
80
+ params = super().enrich_default_params(params, default_params)
81
+ params.setdefault("use_tls", True)
82
+ params.setdefault("start_tls", False)
83
+ params.setdefault("validate_certs", True)
84
+ params.setdefault("server_port", DEFAULT_SMTP_PORT)
85
+
86
+ default_mail_address = params.pop("default_email_addresses", "")
87
+ email_addresses = params.get("email_addresses", default_mail_address)
88
+ if isinstance(email_addresses, list):
89
+ email_addresses = ",".join(email_addresses)
90
+ params["email_addresses"] = email_addresses
91
+
92
+ return params
93
+
94
+ @classmethod
95
+ def _validate_emails(cls, params):
96
+ cls._validate_email_address(params["sender_address"])
97
+
98
+ if not isinstance(params["email_addresses"], (str, list)):
99
+ raise ValueError(
100
+ "Parameter 'email_addresses' must be a string or a list of strings"
101
+ )
102
+
103
+ email_addresses = params["email_addresses"]
104
+ if isinstance(email_addresses, str):
105
+ email_addresses = email_addresses.split(",")
106
+ for email_address in email_addresses:
107
+ cls._validate_email_address(email_address)
108
+
109
+ @classmethod
110
+ def _validate_email_address(cls, email_address):
111
+ if not isinstance(email_address, str):
112
+ raise ValueError(f"Email address '{email_address}' must be a string")
113
+
114
+ if not re.match(mlrun.utils.regex.mail_regex, email_address):
115
+ raise ValueError(f"Invalid email address '{email_address}'")
116
+
117
+ @staticmethod
118
+ async def _send_email(
119
+ email_addresses: str,
120
+ sender_address: str,
121
+ server_host: str,
122
+ server_port: int,
123
+ username: str,
124
+ password: str,
125
+ use_tls: bool,
126
+ start_tls: bool,
127
+ validate_certs: bool,
128
+ subject: str,
129
+ body: str,
130
+ **kwargs,
131
+ ):
132
+ # Create the email message
133
+ message = EmailMessage()
134
+ message["From"] = sender_address
135
+ message["To"] = email_addresses
136
+ message["Subject"] = subject
137
+ message.set_content(body)
138
+
139
+ # Send the email
140
+ await aiosmtplib.send(
141
+ message,
142
+ hostname=server_host,
143
+ port=server_port,
144
+ username=username,
145
+ password=password,
146
+ use_tls=use_tls,
147
+ validate_certs=validate_certs,
148
+ start_tls=start_tls,
149
+ )
@@ -46,13 +46,13 @@ class SlackNotification(NotificationBase):
46
46
  async def push(
47
47
  self,
48
48
  message: str,
49
- severity: typing.Union[
50
- mlrun.common.schemas.NotificationSeverity, str
49
+ severity: typing.Optional[
50
+ typing.Union[mlrun.common.schemas.NotificationSeverity, str]
51
51
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
52
- runs: typing.Union[mlrun.lists.RunList, list] = None,
53
- custom_html: str = None,
54
- alert: mlrun.common.schemas.AlertConfig = None,
55
- event_data: mlrun.common.schemas.Event = None,
52
+ runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
53
+ custom_html: typing.Optional[typing.Optional[str]] = None,
54
+ alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
55
+ event_data: typing.Optional[mlrun.common.schemas.Event] = None,
56
56
  ):
57
57
  webhook = self.params.get("webhook", None) or mlrun.get_secret_or_env(
58
58
  "SLACK_WEBHOOK"
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import re
16
15
  import typing
17
16
 
18
17
  import aiohttp
@@ -38,13 +37,13 @@ class WebhookNotification(NotificationBase):
38
37
  async def push(
39
38
  self,
40
39
  message: str,
41
- severity: typing.Union[
42
- mlrun.common.schemas.NotificationSeverity, str
40
+ severity: typing.Optional[
41
+ typing.Union[mlrun.common.schemas.NotificationSeverity, str]
43
42
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
44
- runs: typing.Union[mlrun.lists.RunList, list] = None,
45
- custom_html: str = None,
46
- alert: mlrun.common.schemas.AlertConfig = None,
47
- event_data: mlrun.common.schemas.Event = None,
43
+ runs: typing.Optional[typing.Union[mlrun.lists.RunList, list]] = None,
44
+ custom_html: typing.Optional[typing.Optional[str]] = None,
45
+ alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
46
+ event_data: typing.Optional[mlrun.common.schemas.Event] = None,
48
47
  ):
49
48
  url = self.params.get("url", None)
50
49
  method = self.params.get("method", "post").lower()
@@ -94,6 +93,7 @@ class WebhookNotification(NotificationBase):
94
93
 
95
94
  @staticmethod
96
95
  def _serialize_runs_in_request_body(override_body, runs):
96
+ str_parsed_runs = ""
97
97
  runs = runs or []
98
98
 
99
99
  def parse_runs():
@@ -105,26 +105,22 @@ class WebhookNotification(NotificationBase):
105
105
  parsed_run = {
106
106
  "project": run["metadata"]["project"],
107
107
  "name": run["metadata"]["name"],
108
+ "host": run["metadata"]["labels"]["host"],
108
109
  "status": {"state": run["status"]["state"]},
109
110
  }
110
- if host := run["metadata"].get("labels", {}).get("host", ""):
111
- parsed_run["host"] = host
112
- if error := run["status"].get("error"):
113
- parsed_run["status"]["error"] = error
114
- elif results := run["status"].get("results"):
115
- parsed_run["status"]["results"] = results
111
+ if run["status"].get("error", None):
112
+ parsed_run["status"]["error"] = run["status"]["error"]
113
+ elif run["status"].get("results", None):
114
+ parsed_run["status"]["results"] = run["status"]["results"]
116
115
  parsed_runs.append(parsed_run)
117
116
  return str(parsed_runs)
118
117
 
119
118
  if isinstance(override_body, dict):
120
119
  for key, value in override_body.items():
121
- if not isinstance(value, str):
122
- # If the value is not a string, we don't want to parse it
123
- continue
124
- if re.search(r"{{\s*runs\s*}}", value):
125
- str_parsed_runs = parse_runs()
126
- override_body[key] = re.sub(
127
- r"{{\s*runs\s*}}", str_parsed_runs, value
128
- )
129
-
120
+ if "{{ runs }}" or "{{runs}}" in value:
121
+ if not str_parsed_runs:
122
+ str_parsed_runs = parse_runs()
123
+ override_body[key] = value.replace(
124
+ "{{ runs }}", str_parsed_runs
125
+ ).replace("{{runs}}", str_parsed_runs)
130
126
  return override_body
@@ -20,10 +20,6 @@ import traceback
20
20
  import typing
21
21
  from concurrent.futures import ThreadPoolExecutor
22
22
 
23
- import mlrun_pipelines.common.ops
24
- import mlrun_pipelines.models
25
- import mlrun_pipelines.utils
26
-
27
23
  import mlrun.common.constants as mlrun_constants
28
24
  import mlrun.common.runtimes.constants
29
25
  import mlrun.common.schemas
@@ -33,11 +29,14 @@ import mlrun.errors
33
29
  import mlrun.lists
34
30
  import mlrun.model
35
31
  import mlrun.utils.helpers
32
+ import mlrun.utils.notifications.notification as notification_module
33
+ import mlrun.utils.notifications.notification.base as base
34
+ import mlrun_pipelines.common.ops
35
+ import mlrun_pipelines.models
36
+ import mlrun_pipelines.utils
36
37
  from mlrun.utils import logger
37
38
  from mlrun.utils.condition_evaluator import evaluate_condition_in_separate_process
38
39
 
39
- from .notification import NotificationBase, NotificationTypes
40
-
41
40
 
42
41
  class _NotificationPusherBase:
43
42
  def _push(
@@ -100,13 +99,22 @@ class NotificationPusher(_NotificationPusherBase):
100
99
  "aborted": "{resource} aborted",
101
100
  }
102
101
 
103
- def __init__(self, runs: typing.Union[mlrun.lists.RunList, list]):
102
+ def __init__(
103
+ self,
104
+ runs: typing.Union[mlrun.lists.RunList, list],
105
+ default_params: typing.Optional[dict] = None,
106
+ ):
104
107
  self._runs = runs
108
+ self._default_params = default_params or {}
105
109
  self._sync_notifications: list[
106
- tuple[NotificationBase, mlrun.model.RunObject, mlrun.model.Notification]
110
+ tuple[
111
+ base.NotificationBase, mlrun.model.RunObject, mlrun.model.Notification
112
+ ]
107
113
  ] = []
108
114
  self._async_notifications: list[
109
- tuple[NotificationBase, mlrun.model.RunObject, mlrun.model.Notification]
115
+ tuple[
116
+ base.NotificationBase, mlrun.model.RunObject, mlrun.model.Notification
117
+ ]
110
118
  ] = []
111
119
 
112
120
  for run in self._runs:
@@ -168,11 +176,6 @@ class NotificationPusher(_NotificationPusherBase):
168
176
  logger.warning(
169
177
  "Failed to push notification async",
170
178
  error=mlrun.errors.err_to_str(result),
171
- traceback=traceback.format_exception(
172
- etype=type(result),
173
- value=result,
174
- tb=result.__traceback__,
175
- ),
176
179
  )
177
180
 
178
181
  logger.debug(
@@ -217,15 +220,18 @@ class NotificationPusher(_NotificationPusherBase):
217
220
 
218
221
  def _load_notification(
219
222
  self, run: mlrun.model.RunObject, notification_object: mlrun.model.Notification
220
- ) -> NotificationBase:
223
+ ) -> base.NotificationBase:
221
224
  name = notification_object.name
222
- notification_type = NotificationTypes(
223
- notification_object.kind or NotificationTypes.console
225
+ notification_type = notification_module.NotificationTypes(
226
+ notification_object.kind or notification_module.NotificationTypes.console
224
227
  )
225
228
  params = {}
226
229
  params.update(notification_object.secret_params)
227
230
  params.update(notification_object.params)
228
- notification = notification_type.get_notification()(name, params)
231
+ default_params = self._default_params.get(notification_type.value, {})
232
+ notification = notification_type.get_notification()(
233
+ name, params, default_params
234
+ )
229
235
  if notification.is_async:
230
236
  self._async_notifications.append((notification, run, notification_object))
231
237
  else:
@@ -265,7 +271,7 @@ class NotificationPusher(_NotificationPusherBase):
265
271
 
266
272
  def _push_notification_sync(
267
273
  self,
268
- notification: NotificationBase,
274
+ notification: base.NotificationBase,
269
275
  run: mlrun.model.RunObject,
270
276
  notification_object: mlrun.model.Notification,
271
277
  ):
@@ -313,7 +319,7 @@ class NotificationPusher(_NotificationPusherBase):
313
319
 
314
320
  async def _push_notification_async(
315
321
  self,
316
- notification: NotificationBase,
322
+ notification: base.NotificationBase,
317
323
  run: mlrun.model.RunObject,
318
324
  notification_object: mlrun.model.Notification,
319
325
  ):
@@ -366,7 +372,7 @@ class NotificationPusher(_NotificationPusherBase):
366
372
  run_uid: str,
367
373
  project: str,
368
374
  notification: mlrun.model.Notification,
369
- status: str = None,
375
+ status: typing.Optional[str] = None,
370
376
  sent_time: typing.Optional[datetime.datetime] = None,
371
377
  reason: typing.Optional[str] = None,
372
378
  ):
@@ -521,9 +527,11 @@ class NotificationPusher(_NotificationPusherBase):
521
527
 
522
528
 
523
529
  class CustomNotificationPusher(_NotificationPusherBase):
524
- def __init__(self, notification_types: list[str] = None):
530
+ def __init__(self, notification_types: typing.Optional[list[str]] = None):
525
531
  notifications = {
526
- notification_type: NotificationTypes(notification_type).get_notification()()
532
+ notification_type: notification_module.NotificationTypes(
533
+ notification_type
534
+ ).get_notification()()
527
535
  for notification_type in notification_types
528
536
  }
529
537
  self._sync_notifications = {
@@ -550,7 +558,7 @@ class CustomNotificationPusher(_NotificationPusherBase):
550
558
  mlrun.common.schemas.NotificationSeverity, str
551
559
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
552
560
  runs: typing.Union[mlrun.lists.RunList, list] = None,
553
- custom_html: str = None,
561
+ custom_html: typing.Optional[str] = None,
554
562
  ):
555
563
  def sync_push():
556
564
  for notification_type, notification in self._sync_notifications.items():
@@ -572,14 +580,16 @@ class CustomNotificationPusher(_NotificationPusherBase):
572
580
  def add_notification(
573
581
  self,
574
582
  notification_type: str,
575
- params: dict[str, str] = None,
583
+ params: typing.Optional[dict[str, str]] = None,
576
584
  ):
577
585
  if notification_type in self._async_notifications:
578
586
  self._async_notifications[notification_type].load_notification(params)
579
587
  elif notification_type in self._sync_notifications:
580
588
  self._sync_notifications[notification_type].load_notification(params)
581
589
  else:
582
- notification = NotificationTypes(notification_type).get_notification()(
590
+ notification = notification_module.NotificationTypes(
591
+ notification_type
592
+ ).get_notification()(
583
593
  params=params,
584
594
  )
585
595
  if notification.is_async:
@@ -597,7 +607,9 @@ class CustomNotificationPusher(_NotificationPusherBase):
597
607
  else:
598
608
  logger.warning(f"No notification of type {notification_type} in project")
599
609
 
600
- def edit_notification(self, notification_type: str, params: dict[str, str] = None):
610
+ def edit_notification(
611
+ self, notification_type: str, params: typing.Optional[dict[str, str]] = None
612
+ ):
601
613
  self.remove_notification(notification_type)
602
614
  self.add_notification(notification_type, params)
603
615
 
@@ -611,7 +623,7 @@ class CustomNotificationPusher(_NotificationPusherBase):
611
623
 
612
624
  # get notification's inverse dependencies, and only push the notification if
613
625
  # none of its inverse dependencies are being sent
614
- inverse_dependencies = NotificationTypes(
626
+ inverse_dependencies = notification_module.NotificationTypes(
615
627
  notification_type
616
628
  ).inverse_dependencies()
617
629
  for inverse_dependency in inverse_dependencies:
@@ -627,8 +639,8 @@ class CustomNotificationPusher(_NotificationPusherBase):
627
639
  def push_pipeline_start_message(
628
640
  self,
629
641
  project: str,
630
- commit_id: str = None,
631
- pipeline_id: str = None,
642
+ commit_id: typing.Optional[str] = None,
643
+ pipeline_id: typing.Optional[str] = None,
632
644
  has_workflow_url: bool = False,
633
645
  ):
634
646
  message = f"Workflow started in project {project}"
@@ -656,7 +668,7 @@ class CustomNotificationPusher(_NotificationPusherBase):
656
668
  self,
657
669
  runs: typing.Union[mlrun.lists.RunList, list],
658
670
  push_all: bool = False,
659
- state: str = None,
671
+ state: typing.Optional[str] = None,
660
672
  ):
661
673
  """
662
674
  push a structured table with run results to notification targets
mlrun/utils/regex.py CHANGED
@@ -86,7 +86,7 @@ tag_name = label_value
86
86
 
87
87
  secret_key = k8s_secret_and_config_map_key
88
88
 
89
- artifact_key = [r"[^\/\\]+$"]
89
+ artifact_key = [r"^[A-Za-z0-9]([-A-Za-z0-9_.]*[A-Za-z0-9])?$"]
90
90
 
91
91
  # must not start with _
92
92
  # must be alphanumeric or _
@@ -101,3 +101,5 @@ artifact_uri_pattern = r"^((?P<project>.*)/)?(?P<key>.*?)(\#(?P<iteration>.*?))?
101
101
  artifact_producer_uri_pattern = (
102
102
  r"^((?P<project>.*)/)?(?P<uid>.*?)(\-(?P<iteration>.*?))?$"
103
103
  )
104
+
105
+ mail_regex = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "3440c50863afd3b3dd850ade4ee237e8a1eb3211",
3
- "version": "1.7.2-rc3"
2
+ "git_commit": "d1bac86097b49ad1b459421723c455622e88e5b3",
3
+ "version": "1.8.0-rc2"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mlrun
3
- Version: 1.7.2rc3
3
+ Version: 1.8.0rc2
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -23,35 +23,37 @@ Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: urllib3<1.27,>=1.26.9
25
25
  Requires-Dist: GitPython>=3.1.41,~=3.1
26
- Requires-Dist: aiohttp<3.11,>=3.9
26
+ Requires-Dist: aiohttp~=3.10.0
27
27
  Requires-Dist: aiohttp-retry~=2.8.0
28
28
  Requires-Dist: click~=8.1
29
29
  Requires-Dist: nest-asyncio~=1.0
30
30
  Requires-Dist: ipython~=8.10
31
- Requires-Dist: nuclio-jupyter~=0.10.4
32
- Requires-Dist: numpy<1.27.0,>=1.16.5
31
+ Requires-Dist: nuclio-jupyter~=0.11.1
32
+ Requires-Dist: numpy<1.27.0,>=1.26.4
33
33
  Requires-Dist: pandas<2.2,>=1.2
34
34
  Requires-Dist: pyarrow<18,>=10.0
35
35
  Requires-Dist: pyyaml<7,>=5.4.1
36
36
  Requires-Dist: requests~=2.32
37
37
  Requires-Dist: tabulate~=0.8.6
38
38
  Requires-Dist: v3io~=0.6.9
39
- Requires-Dist: pydantic<1.10.15,>=1.10.8
39
+ Requires-Dist: pydantic>=1.10.15
40
40
  Requires-Dist: mergedeep~=1.3
41
41
  Requires-Dist: v3io-frames~=0.10.14
42
42
  Requires-Dist: semver~=3.0
43
43
  Requires-Dist: dependency-injector~=4.41
44
44
  Requires-Dist: fsspec<2024.7,>=2023.9.2
45
45
  Requires-Dist: v3iofs~=0.1.17
46
- Requires-Dist: storey~=1.7.50
46
+ Requires-Dist: storey~=1.8.0
47
47
  Requires-Dist: inflection~=0.5.0
48
- Requires-Dist: python-dotenv~=0.17.0
49
- Requires-Dist: setuptools~=71.0
48
+ Requires-Dist: python-dotenv~=1.0
49
+ Requires-Dist: setuptools>=75.2
50
50
  Requires-Dist: deprecated~=1.2
51
51
  Requires-Dist: jinja2>=3.1.3,~=3.1
52
52
  Requires-Dist: orjson<4,>=3.9.15
53
- Requires-Dist: mlrun-pipelines-kfp-common~=0.1.9
54
- Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.1.6
53
+ Requires-Dist: mlrun-pipelines-kfp-common~=0.2.2
54
+ Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.1
55
+ Requires-Dist: docstring_parser~=0.16
56
+ Requires-Dist: aiosmtplib~=3.0
55
57
  Provides-Extra: s3
56
58
  Requires-Dist: boto3<1.36,>=1.28.0; extra == "s3"
57
59
  Requires-Dist: aiobotocore<2.16,>=2.5.0; extra == "s3"
@@ -102,9 +104,9 @@ Requires-Dist: snowflake-connector-python~=3.7; extra == "snowflake"
102
104
  Provides-Extra: api
103
105
  Requires-Dist: uvicorn~=0.27.1; extra == "api"
104
106
  Requires-Dist: dask-kubernetes~=0.11.0; extra == "api"
105
- Requires-Dist: apscheduler==3.10.3; extra == "api"
107
+ Requires-Dist: apscheduler<4,>=3.10.3; extra == "api"
106
108
  Requires-Dist: objgraph~=3.6; extra == "api"
107
- Requires-Dist: igz-mgmt~=0.2.0; extra == "api"
109
+ Requires-Dist: igz-mgmt~=0.4.1; extra == "api"
108
110
  Requires-Dist: humanfriendly~=10.0; extra == "api"
109
111
  Requires-Dist: fastapi~=0.110.0; extra == "api"
110
112
  Requires-Dist: sqlalchemy~=1.4; extra == "api"
@@ -112,6 +114,7 @@ Requires-Dist: pymysql~=1.0; extra == "api"
112
114
  Requires-Dist: alembic~=1.9; extra == "api"
113
115
  Requires-Dist: timelength~=1.1; extra == "api"
114
116
  Requires-Dist: memray~=1.12; sys_platform != "win32" and extra == "api"
117
+ Requires-Dist: aiosmtplib~=3.0; extra == "api"
115
118
  Provides-Extra: all
116
119
  Requires-Dist: adlfs==2023.9.0; extra == "all"
117
120
  Requires-Dist: aiobotocore<2.16,>=2.5.0; extra == "all"
@@ -176,8 +179,9 @@ Requires-Dist: taoswswrap~=0.2.0; extra == "complete"
176
179
  Provides-Extra: complete-api
177
180
  Requires-Dist: adlfs==2023.9.0; extra == "complete-api"
178
181
  Requires-Dist: aiobotocore<2.16,>=2.5.0; extra == "complete-api"
182
+ Requires-Dist: aiosmtplib~=3.0; extra == "complete-api"
179
183
  Requires-Dist: alembic~=1.9; extra == "complete-api"
180
- Requires-Dist: apscheduler==3.10.3; extra == "complete-api"
184
+ Requires-Dist: apscheduler<4,>=3.10.3; extra == "complete-api"
181
185
  Requires-Dist: avro~=1.11; extra == "complete-api"
182
186
  Requires-Dist: azure-core~=1.24; extra == "complete-api"
183
187
  Requires-Dist: azure-identity~=1.5; extra == "complete-api"
@@ -195,7 +199,7 @@ Requires-Dist: google-cloud-storage==2.14.0; extra == "complete-api"
195
199
  Requires-Dist: google-cloud==0.34; extra == "complete-api"
196
200
  Requires-Dist: graphviz~=0.20.0; extra == "complete-api"
197
201
  Requires-Dist: humanfriendly~=10.0; extra == "complete-api"
198
- Requires-Dist: igz-mgmt~=0.2.0; extra == "complete-api"
202
+ Requires-Dist: igz-mgmt~=0.4.1; extra == "complete-api"
199
203
  Requires-Dist: kafka-python~=2.0; extra == "complete-api"
200
204
  Requires-Dist: memray~=1.12; sys_platform != "win32" and extra == "complete-api"
201
205
  Requires-Dist: mlflow~=2.8; extra == "complete-api"