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
mlrun/utils/logger.py CHANGED
@@ -11,9 +11,11 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
-
14
+ import datetime
15
15
  import logging
16
16
  import os
17
+ import string
18
+ import sys
17
19
  import typing
18
20
  from enum import Enum
19
21
  from functools import cached_property
@@ -24,6 +26,7 @@ from typing import IO, Optional, Union
24
26
  import orjson
25
27
  import pydantic
26
28
 
29
+ from mlrun import errors
27
30
  from mlrun.config import config
28
31
 
29
32
 
@@ -93,6 +96,98 @@ class HumanReadableFormatter(_BaseFormatter):
93
96
  return record_with
94
97
 
95
98
 
99
+ class CustomFormatter(HumanReadableFormatter):
100
+ """
101
+ To enable custom logger formatter, configure MLRun with the following env variables:
102
+ 1. "MLRUN_LOG_FORMATTER" = "custom" - change the default log formatter.
103
+ 2. "MLRUN_LOG_FORMAT_OVERRIDE" = "> {timestamp} [{level}] Running module: {module} {message} {more}" - logger format
104
+ * Note that your custom format must include those 4 fields - timestamp, level, message and more
105
+ If the custom format is not configured properly , MLRun will use the default logger (human format).
106
+ """
107
+
108
+ # This attribute is used to solve an issue
109
+ # that causes the warning to be written numerous times(for any log generation).
110
+ # We want to print the errors just once, not for each logger generation.
111
+ fail_on_format_configuration = False # for issues that relates to unrecognized keys
112
+ fail_on_missing_default_keys_key = (
113
+ False # for issues that relates to missing default keys
114
+ )
115
+
116
+ def format(self, record) -> str:
117
+ more = self._resolve_more(record)
118
+ custom_format = config.log_format_override
119
+ _custom_format = None
120
+ current_time = datetime.datetime.now()
121
+ formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S,%f")[:-3]
122
+ try:
123
+ if custom_format:
124
+ default_keys = ["timestamp", "level", "message", "more"]
125
+ formatter = string.Formatter()
126
+ custom_format_keys = [
127
+ key
128
+ for _, key, _, _ in formatter.parse(custom_format)
129
+ if key is not None
130
+ ]
131
+ missing_default_flags = list(
132
+ set(default_keys) - set(custom_format_keys)
133
+ )
134
+
135
+ if (
136
+ missing_default_flags
137
+ and not CustomFormatter.fail_on_missing_default_keys_key
138
+ ):
139
+ print(
140
+ f'> {formatted_time} [warning] Custom loggers must '
141
+ f'include those keys within the logger format, {", ".join(default_keys)} '
142
+ f'your format is missing: {", ".join(missing_default_flags)}',
143
+ file=sys.stderr,
144
+ )
145
+ CustomFormatter.fail_on_missing_default_keys_key = True
146
+ record_dict = record.__dict__
147
+ missing_format_configuraiton_keys = list(
148
+ set(custom_format_keys)
149
+ - set(default_keys)
150
+ - set(record_dict.keys())
151
+ )
152
+ if missing_format_configuraiton_keys:
153
+ if not CustomFormatter.fail_on_format_configuration:
154
+ print(
155
+ f"> {formatted_time} [warning] Failed to create custom logger due "
156
+ f'to missing format key in the log record: {", ".join(missing_format_configuraiton_keys)}',
157
+ file=sys.stderr,
158
+ )
159
+ CustomFormatter.fail_on_format_configuration = True
160
+ _format = (
161
+ f"> {self.formatTime(record, self.datefmt)} "
162
+ f"[{record.levelname.lower()}] "
163
+ f"{record.getMessage().rstrip()}"
164
+ f"{more}"
165
+ )
166
+ _custom_format = custom_format.format(
167
+ timestamp=self.formatTime(record, self.datefmt),
168
+ level=record.levelname.lower(),
169
+ message=record.getMessage().rstrip(),
170
+ more=more or "",
171
+ **record_dict,
172
+ )
173
+ CustomFormatter.fail_on_format_configuration = True
174
+ except Exception as e:
175
+ if not CustomFormatter.fail_on_format_configuration:
176
+ print(
177
+ f"> {formatted_time} [warning] Failed to create custom logger, "
178
+ f"see Exception: {errors.err_to_str(e)}",
179
+ file=sys.stderr,
180
+ )
181
+ CustomFormatter.fail_on_format_configuration = True
182
+ _format = _custom_format or (
183
+ f"> {self.formatTime(record, self.datefmt)} "
184
+ f"[{record.levelname.lower()}] "
185
+ f"{record.getMessage().rstrip()}"
186
+ f"{more}"
187
+ )
188
+ return _format
189
+
190
+
96
191
  class HumanReadableExtendedFormatter(HumanReadableFormatter):
97
192
  _colors = {
98
193
  logging.NOTSET: "",
@@ -272,17 +367,24 @@ class FormatterKinds(Enum):
272
367
  HUMAN = "human"
273
368
  HUMAN_EXTENDED = "human_extended"
274
369
  JSON = "json"
370
+ CUSTOM = "custom"
275
371
 
276
372
 
277
373
  def resolve_formatter_by_kind(
278
374
  formatter_kind: FormatterKinds,
279
375
  ) -> type[
280
- typing.Union[HumanReadableFormatter, HumanReadableExtendedFormatter, JSONFormatter]
376
+ typing.Union[
377
+ HumanReadableFormatter,
378
+ HumanReadableExtendedFormatter,
379
+ JSONFormatter,
380
+ CustomFormatter,
381
+ ]
281
382
  ]:
282
383
  return {
283
384
  FormatterKinds.HUMAN: HumanReadableFormatter,
284
385
  FormatterKinds.HUMAN_EXTENDED: HumanReadableExtendedFormatter,
285
386
  FormatterKinds.JSON: JSONFormatter,
387
+ FormatterKinds.CUSTOM: CustomFormatter,
286
388
  }[formatter_kind]
287
389
 
288
390
 
@@ -14,6 +14,7 @@
14
14
 
15
15
  import asyncio
16
16
  import typing
17
+ from copy import deepcopy
17
18
 
18
19
  import mlrun.common.schemas
19
20
  import mlrun.lists
@@ -22,11 +23,20 @@ import mlrun.lists
22
23
  class NotificationBase:
23
24
  def __init__(
24
25
  self,
25
- name: str = None,
26
- params: dict[str, str] = None,
26
+ name: typing.Optional[str] = None,
27
+ params: typing.Optional[dict[str, str]] = None,
28
+ default_params: typing.Optional[dict[str, str]] = None,
27
29
  ):
30
+ """
31
+ NotificationBase is the base class for all notification types.
32
+
33
+ :param name: The name of the notification.
34
+ :param params: The parameters of the notification.
35
+ :param default_params: The default parameters of the notification. Used for server-side enrichment purposes.
36
+ """
28
37
  self.name = name
29
38
  self.params = params or {}
39
+ self.params = self.enrich_default_params(self.params, default_params)
30
40
 
31
41
  @classmethod
32
42
  def validate_params(cls, params):
@@ -47,7 +57,7 @@ class NotificationBase:
47
57
  mlrun.common.schemas.NotificationSeverity, str
48
58
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
49
59
  runs: typing.Union[mlrun.lists.RunList, list] = None,
50
- custom_html: str = None,
60
+ custom_html: typing.Optional[str] = None,
51
61
  alert: mlrun.common.schemas.AlertConfig = None,
52
62
  event_data: mlrun.common.schemas.Event = None,
53
63
  ):
@@ -59,6 +69,15 @@ class NotificationBase:
59
69
  ) -> None:
60
70
  self.params = params or {}
61
71
 
72
+ @classmethod
73
+ def enrich_default_params(
74
+ cls, params: dict, default_params: typing.Optional[dict] = None
75
+ ) -> dict:
76
+ default_params = default_params or {}
77
+ returned_params = deepcopy(default_params)
78
+ returned_params.update(params)
79
+ return returned_params
80
+
62
81
  def _get_html(
63
82
  self,
64
83
  message: str,
@@ -66,7 +85,7 @@ class NotificationBase:
66
85
  mlrun.common.schemas.NotificationSeverity, str
67
86
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
68
87
  runs: typing.Union[mlrun.lists.RunList, list] = None,
69
- custom_html: str = None,
88
+ custom_html: typing.Optional[str] = None,
70
89
  alert: mlrun.common.schemas.AlertConfig = None,
71
90
  event_data: mlrun.common.schemas.Event = None,
72
91
  ) -> str:
@@ -35,7 +35,7 @@ class ConsoleNotification(NotificationBase):
35
35
  mlrun.common.schemas.NotificationSeverity, str
36
36
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
37
37
  runs: typing.Union[mlrun.lists.RunList, list] = None,
38
- custom_html: str = None,
38
+ custom_html: typing.Optional[str] = None,
39
39
  alert: mlrun.common.schemas.AlertConfig = None,
40
40
  event_data: mlrun.common.schemas.Event = None,
41
41
  ):
@@ -58,7 +58,7 @@ class GitNotification(NotificationBase):
58
58
  mlrun.common.schemas.NotificationSeverity, str
59
59
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
60
60
  runs: typing.Union[mlrun.lists.RunList, list] = None,
61
- custom_html: str = None,
61
+ custom_html: typing.Optional[str] = None,
62
62
  alert: mlrun.common.schemas.AlertConfig = None,
63
63
  event_data: mlrun.common.schemas.Event = None,
64
64
  ):
@@ -85,11 +85,11 @@ class GitNotification(NotificationBase):
85
85
  @staticmethod
86
86
  async def _pr_comment(
87
87
  message: str,
88
- repo: str = None,
89
- issue: int = None,
90
- merge_request: int = None,
91
- token: str = None,
92
- server: str = None,
88
+ repo: typing.Optional[str] = None,
89
+ issue: typing.Optional[int] = None,
90
+ merge_request: typing.Optional[int] = None,
91
+ token: typing.Optional[str] = None,
92
+ server: typing.Optional[str] = None,
93
93
  gitlab: bool = False,
94
94
  ) -> str:
95
95
  """push comment message to Git system PR/issue
@@ -28,10 +28,11 @@ class IPythonNotification(NotificationBase):
28
28
 
29
29
  def __init__(
30
30
  self,
31
- name: str = None,
32
- params: dict[str, str] = None,
31
+ name: typing.Optional[str] = None,
32
+ params: typing.Optional[dict[str, str]] = None,
33
+ default_params: typing.Optional[dict[str, str]] = None,
33
34
  ):
34
- super().__init__(name, params)
35
+ super().__init__(name, params, default_params)
35
36
  self._ipython = None
36
37
  try:
37
38
  import IPython
@@ -52,7 +53,7 @@ class IPythonNotification(NotificationBase):
52
53
  mlrun.common.schemas.NotificationSeverity, str
53
54
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
54
55
  runs: typing.Union[mlrun.lists.RunList, list] = None,
55
- custom_html: str = None,
56
+ custom_html: typing.Optional[str] = None,
56
57
  alert: mlrun.common.schemas.AlertConfig = None,
57
58
  event_data: mlrun.common.schemas.Event = None,
58
59
  ):
@@ -50,7 +50,7 @@ class SlackNotification(NotificationBase):
50
50
  mlrun.common.schemas.NotificationSeverity, str
51
51
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
52
52
  runs: typing.Union[mlrun.lists.RunList, list] = None,
53
- custom_html: str = None,
53
+ custom_html: typing.Optional[str] = None,
54
54
  alert: mlrun.common.schemas.AlertConfig = None,
55
55
  event_data: mlrun.common.schemas.Event = None,
56
56
  ):
@@ -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
@@ -42,7 +41,7 @@ class WebhookNotification(NotificationBase):
42
41
  mlrun.common.schemas.NotificationSeverity, str
43
42
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
44
43
  runs: typing.Union[mlrun.lists.RunList, list] = None,
45
- custom_html: str = None,
44
+ custom_html: typing.Optional[str] = None,
46
45
  alert: mlrun.common.schemas.AlertConfig = None,
47
46
  event_data: mlrun.common.schemas.Event = None,
48
47
  ):
@@ -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,6 +29,9 @@ import mlrun.errors
33
29
  import mlrun.lists
34
30
  import mlrun.model
35
31
  import mlrun.utils.helpers
32
+ import mlrun_pipelines.common.ops
33
+ import mlrun_pipelines.models
34
+ import mlrun_pipelines.utils
36
35
  from mlrun.utils import logger
37
36
  from mlrun.utils.condition_evaluator import evaluate_condition_in_separate_process
38
37
 
@@ -100,8 +99,13 @@ 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
110
  tuple[NotificationBase, mlrun.model.RunObject, mlrun.model.Notification]
107
111
  ] = []
@@ -168,11 +172,6 @@ class NotificationPusher(_NotificationPusherBase):
168
172
  logger.warning(
169
173
  "Failed to push notification async",
170
174
  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
175
  )
177
176
 
178
177
  logger.debug(
@@ -225,7 +224,10 @@ class NotificationPusher(_NotificationPusherBase):
225
224
  params = {}
226
225
  params.update(notification_object.secret_params)
227
226
  params.update(notification_object.params)
228
- notification = notification_type.get_notification()(name, params)
227
+ default_params = self._default_params.get(notification_type.value, {})
228
+ notification = notification_type.get_notification()(
229
+ name, params, default_params
230
+ )
229
231
  if notification.is_async:
230
232
  self._async_notifications.append((notification, run, notification_object))
231
233
  else:
@@ -366,7 +368,7 @@ class NotificationPusher(_NotificationPusherBase):
366
368
  run_uid: str,
367
369
  project: str,
368
370
  notification: mlrun.model.Notification,
369
- status: str = None,
371
+ status: typing.Optional[str] = None,
370
372
  sent_time: typing.Optional[datetime.datetime] = None,
371
373
  reason: typing.Optional[str] = None,
372
374
  ):
@@ -521,7 +523,7 @@ class NotificationPusher(_NotificationPusherBase):
521
523
 
522
524
 
523
525
  class CustomNotificationPusher(_NotificationPusherBase):
524
- def __init__(self, notification_types: list[str] = None):
526
+ def __init__(self, notification_types: typing.Optional[list[str]] = None):
525
527
  notifications = {
526
528
  notification_type: NotificationTypes(notification_type).get_notification()()
527
529
  for notification_type in notification_types
@@ -550,7 +552,7 @@ class CustomNotificationPusher(_NotificationPusherBase):
550
552
  mlrun.common.schemas.NotificationSeverity, str
551
553
  ] = mlrun.common.schemas.NotificationSeverity.INFO,
552
554
  runs: typing.Union[mlrun.lists.RunList, list] = None,
553
- custom_html: str = None,
555
+ custom_html: typing.Optional[str] = None,
554
556
  ):
555
557
  def sync_push():
556
558
  for notification_type, notification in self._sync_notifications.items():
@@ -572,7 +574,7 @@ class CustomNotificationPusher(_NotificationPusherBase):
572
574
  def add_notification(
573
575
  self,
574
576
  notification_type: str,
575
- params: dict[str, str] = None,
577
+ params: typing.Optional[dict[str, str]] = None,
576
578
  ):
577
579
  if notification_type in self._async_notifications:
578
580
  self._async_notifications[notification_type].load_notification(params)
@@ -597,7 +599,9 @@ class CustomNotificationPusher(_NotificationPusherBase):
597
599
  else:
598
600
  logger.warning(f"No notification of type {notification_type} in project")
599
601
 
600
- def edit_notification(self, notification_type: str, params: dict[str, str] = None):
602
+ def edit_notification(
603
+ self, notification_type: str, params: typing.Optional[dict[str, str]] = None
604
+ ):
601
605
  self.remove_notification(notification_type)
602
606
  self.add_notification(notification_type, params)
603
607
 
@@ -627,8 +631,8 @@ class CustomNotificationPusher(_NotificationPusherBase):
627
631
  def push_pipeline_start_message(
628
632
  self,
629
633
  project: str,
630
- commit_id: str = None,
631
- pipeline_id: str = None,
634
+ commit_id: typing.Optional[str] = None,
635
+ pipeline_id: typing.Optional[str] = None,
632
636
  has_workflow_url: bool = False,
633
637
  ):
634
638
  message = f"Workflow started in project {project}"
@@ -656,7 +660,7 @@ class CustomNotificationPusher(_NotificationPusherBase):
656
660
  self,
657
661
  runs: typing.Union[mlrun.lists.RunList, list],
658
662
  push_all: bool = False,
659
- state: str = None,
663
+ state: typing.Optional[str] = None,
660
664
  ):
661
665
  """
662
666
  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 _
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "3440c50863afd3b3dd850ade4ee237e8a1eb3211",
3
- "version": "1.7.2-rc3"
2
+ "git_commit": "f2e5312ff81bf956d90d45964ee2cbbe02c4323f",
3
+ "version": "1.8.0-rc1"
4
4
  }