mlrun 1.7.0rc22__py3-none-any.whl → 1.7.0rc28__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 (81) hide show
  1. mlrun/__main__.py +10 -8
  2. mlrun/alerts/alert.py +13 -1
  3. mlrun/artifacts/manager.py +5 -0
  4. mlrun/common/constants.py +2 -2
  5. mlrun/common/formatters/__init__.py +1 -0
  6. mlrun/common/formatters/artifact.py +26 -3
  7. mlrun/common/formatters/base.py +9 -9
  8. mlrun/common/formatters/run.py +26 -0
  9. mlrun/common/helpers.py +11 -0
  10. mlrun/common/schemas/__init__.py +4 -0
  11. mlrun/common/schemas/alert.py +5 -9
  12. mlrun/common/schemas/api_gateway.py +64 -16
  13. mlrun/common/schemas/artifact.py +11 -0
  14. mlrun/common/schemas/constants.py +3 -0
  15. mlrun/common/schemas/feature_store.py +58 -28
  16. mlrun/common/schemas/model_monitoring/constants.py +21 -12
  17. mlrun/common/schemas/model_monitoring/model_endpoints.py +0 -12
  18. mlrun/common/schemas/pipeline.py +16 -0
  19. mlrun/common/schemas/project.py +17 -0
  20. mlrun/common/schemas/runs.py +17 -0
  21. mlrun/common/schemas/schedule.py +1 -1
  22. mlrun/common/types.py +5 -0
  23. mlrun/config.py +10 -25
  24. mlrun/datastore/azure_blob.py +2 -1
  25. mlrun/datastore/datastore.py +3 -3
  26. mlrun/datastore/google_cloud_storage.py +6 -2
  27. mlrun/datastore/snowflake_utils.py +3 -1
  28. mlrun/datastore/sources.py +26 -11
  29. mlrun/datastore/store_resources.py +2 -0
  30. mlrun/datastore/targets.py +68 -16
  31. mlrun/db/base.py +64 -2
  32. mlrun/db/httpdb.py +129 -41
  33. mlrun/db/nopdb.py +44 -3
  34. mlrun/errors.py +5 -3
  35. mlrun/execution.py +18 -10
  36. mlrun/feature_store/retrieval/spark_merger.py +2 -1
  37. mlrun/frameworks/__init__.py +0 -6
  38. mlrun/model.py +23 -0
  39. mlrun/model_monitoring/api.py +6 -52
  40. mlrun/model_monitoring/applications/histogram_data_drift.py +1 -1
  41. mlrun/model_monitoring/db/stores/__init__.py +37 -24
  42. mlrun/model_monitoring/db/stores/base/store.py +40 -1
  43. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +42 -87
  44. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +27 -35
  45. mlrun/model_monitoring/db/tsdb/__init__.py +15 -15
  46. mlrun/model_monitoring/db/tsdb/base.py +1 -1
  47. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +6 -4
  48. mlrun/model_monitoring/helpers.py +17 -9
  49. mlrun/model_monitoring/stream_processing.py +9 -11
  50. mlrun/model_monitoring/writer.py +11 -11
  51. mlrun/package/__init__.py +1 -13
  52. mlrun/package/packagers/__init__.py +1 -6
  53. mlrun/projects/pipelines.py +10 -9
  54. mlrun/projects/project.py +95 -81
  55. mlrun/render.py +10 -5
  56. mlrun/run.py +13 -8
  57. mlrun/runtimes/base.py +11 -4
  58. mlrun/runtimes/daskjob.py +7 -1
  59. mlrun/runtimes/local.py +16 -3
  60. mlrun/runtimes/nuclio/application/application.py +0 -2
  61. mlrun/runtimes/nuclio/function.py +20 -0
  62. mlrun/runtimes/nuclio/serving.py +9 -6
  63. mlrun/runtimes/pod.py +5 -29
  64. mlrun/serving/routers.py +75 -59
  65. mlrun/serving/server.py +11 -0
  66. mlrun/serving/states.py +29 -0
  67. mlrun/serving/v2_serving.py +62 -39
  68. mlrun/utils/helpers.py +39 -1
  69. mlrun/utils/logger.py +36 -2
  70. mlrun/utils/notifications/notification/base.py +43 -7
  71. mlrun/utils/notifications/notification/git.py +21 -0
  72. mlrun/utils/notifications/notification/slack.py +9 -14
  73. mlrun/utils/notifications/notification/webhook.py +41 -1
  74. mlrun/utils/notifications/notification_pusher.py +3 -9
  75. mlrun/utils/version/version.json +2 -2
  76. {mlrun-1.7.0rc22.dist-info → mlrun-1.7.0rc28.dist-info}/METADATA +12 -7
  77. {mlrun-1.7.0rc22.dist-info → mlrun-1.7.0rc28.dist-info}/RECORD +81 -80
  78. {mlrun-1.7.0rc22.dist-info → mlrun-1.7.0rc28.dist-info}/WHEEL +1 -1
  79. {mlrun-1.7.0rc22.dist-info → mlrun-1.7.0rc28.dist-info}/LICENSE +0 -0
  80. {mlrun-1.7.0rc22.dist-info → mlrun-1.7.0rc28.dist-info}/entry_points.txt +0 -0
  81. {mlrun-1.7.0rc22.dist-info → mlrun-1.7.0rc28.dist-info}/top_level.txt +0 -0
@@ -28,6 +28,10 @@ class NotificationBase:
28
28
  self.name = name
29
29
  self.params = params or {}
30
30
 
31
+ @classmethod
32
+ def validate_params(cls, params):
33
+ pass
34
+
31
35
  @property
32
36
  def active(self) -> bool:
33
37
  return True
@@ -69,16 +73,27 @@ class NotificationBase:
69
73
  if custom_html:
70
74
  return custom_html
71
75
 
72
- if self.name:
73
- message = f"{self.name}: {message}"
74
-
75
76
  if alert:
76
77
  if not event_data:
77
78
  return f"[{severity}] {message}"
78
- return (
79
- f"[{severity}] {message} for project {alert.project} "
80
- f"UID {event_data.entity.ids[0]}. Values {event_data.value_dict}"
81
- )
79
+
80
+ html = f"<h3>[{severity}] {message}</h3>"
81
+ html += f"<br>{alert.name} alert has occurred<br>"
82
+ html += f"<br><h4>Project:</h4>{alert.project}<br>"
83
+ html += f"<br><h4>ID:</h4>{event_data.entity.ids[0]}<br>"
84
+ html += f"<br><h4>Summary:</h4>{mlrun.utils.helpers.format_alert_summary(alert, event_data)}<br>"
85
+
86
+ if event_data.value_dict:
87
+ html += "<br><h4>Event data:</h4>"
88
+ for key, value in event_data.value_dict.items():
89
+ html += f"{key}: {value}<br>"
90
+
91
+ overview_type, url = self._get_overview_type_and_url(alert, event_data)
92
+ html += f"<br><h4>Overview:</h4><a href={url}>{overview_type}</a>"
93
+ return html
94
+
95
+ if self.name:
96
+ message = f"{self.name}: {message}"
82
97
 
83
98
  if not runs:
84
99
  return f"[{severity}] {message}"
@@ -90,3 +105,24 @@ class NotificationBase:
90
105
  html += "<br>click the hyper links below to see detailed results<br>"
91
106
  html += runs.show(display=False, short=True)
92
107
  return html
108
+
109
+ def _get_overview_type_and_url(
110
+ self,
111
+ alert: mlrun.common.schemas.AlertConfig,
112
+ event_data: mlrun.common.schemas.Event,
113
+ ) -> (str, str):
114
+ if (
115
+ event_data.entity.kind == mlrun.common.schemas.alert.EventEntityKind.JOB
116
+ ): # JOB entity
117
+ uid = event_data.value_dict.get("uid")
118
+ url = mlrun.utils.helpers.get_ui_url(alert.project, uid)
119
+ overview_type = "Job overview"
120
+ else: # MODEL entity
121
+ model_name = event_data.value_dict.get("model")
122
+ model_endpoint_id = event_data.value_dict.get("model_endpoint_id")
123
+ url = mlrun.utils.helpers.get_model_endpoint_url(
124
+ alert.project, model_name, model_endpoint_id
125
+ )
126
+ overview_type = "Model endpoint"
127
+
128
+ return overview_type, url
@@ -30,6 +30,27 @@ class GitNotification(NotificationBase):
30
30
  API/Client notification for setting a rich run statuses git issue comment (github/gitlab)
31
31
  """
32
32
 
33
+ @classmethod
34
+ def validate_params(cls, params):
35
+ git_repo = params.get("repo", None)
36
+ git_issue = params.get("issue", None)
37
+ git_merge_request = params.get("merge_request", None)
38
+ token = (
39
+ params.get("token", None)
40
+ or params.get("GIT_TOKEN", None)
41
+ or params.get("GITHUB_TOKEN", None)
42
+ )
43
+ if not git_repo:
44
+ raise ValueError("Parameter 'repo' is required for GitNotification")
45
+
46
+ if not token:
47
+ raise ValueError("Parameter 'token' is required for GitNotification")
48
+
49
+ if not git_issue and not git_merge_request:
50
+ raise ValueError(
51
+ "At least one of 'issue' or 'merge_request' is required for GitNotification"
52
+ )
53
+
33
54
  async def push(
34
55
  self,
35
56
  message: str,
@@ -35,6 +35,14 @@ class SlackNotification(NotificationBase):
35
35
  "skipped": ":zzz:",
36
36
  }
37
37
 
38
+ @classmethod
39
+ def validate_params(cls, params):
40
+ webhook = params.get("webhook", None) or mlrun.get_secret_or_env(
41
+ "SLACK_WEBHOOK"
42
+ )
43
+ if not webhook:
44
+ raise ValueError("Parameter 'webhook' is required for SlackNotification")
45
+
38
46
  async def push(
39
47
  self,
40
48
  message: str,
@@ -153,20 +161,7 @@ class SlackNotification(NotificationBase):
153
161
  data_text = "\n".join(data_lines)
154
162
  line.append(self._get_slack_row(f"*Event data:*\n{data_text}"))
155
163
 
156
- if (
157
- event_data.entity.kind == mlrun.common.schemas.alert.EventEntityKind.JOB
158
- ): # JOB entity
159
- uid = event_data.value_dict.get("uid")
160
- url = mlrun.utils.helpers.get_ui_url(alert.project, uid)
161
- overview_type = "Job overview"
162
- else: # MODEL entity
163
- model_name = event_data.value_dict.get("model")
164
- model_endpoint_id = event_data.value_dict.get("model_endpoint_id")
165
- url = mlrun.utils.helpers.get_model_endpoint_url(
166
- alert.project, model_name, model_endpoint_id
167
- )
168
- overview_type = "Model endpoint"
169
-
164
+ overview_type, url = self._get_overview_type_and_url(alert, event_data)
170
165
  line.append(self._get_slack_row(f"*Overview:*\n<{url}|*{overview_type}*>"))
171
166
 
172
167
  return line
@@ -28,6 +28,12 @@ class WebhookNotification(NotificationBase):
28
28
  API/Client notification for sending run statuses in a http request
29
29
  """
30
30
 
31
+ @classmethod
32
+ def validate_params(cls, params):
33
+ url = params.get("url", None)
34
+ if not url:
35
+ raise ValueError("Parameter 'url' is required for WebhookNotification")
36
+
31
37
  async def push(
32
38
  self,
33
39
  message: str,
@@ -63,7 +69,7 @@ class WebhookNotification(NotificationBase):
63
69
  request_body["custom_html"] = custom_html
64
70
 
65
71
  if override_body:
66
- request_body = override_body
72
+ request_body = self._serialize_runs_in_request_body(override_body, runs)
67
73
 
68
74
  # Specify the `verify_ssl` parameter value only for HTTPS urls.
69
75
  # The `ClientSession` allows using `ssl=None` for the default SSL check,
@@ -77,3 +83,37 @@ class WebhookNotification(NotificationBase):
77
83
  url, headers=headers, json=request_body, ssl=verify_ssl
78
84
  )
79
85
  response.raise_for_status()
86
+
87
+ @staticmethod
88
+ def _serialize_runs_in_request_body(override_body, runs):
89
+ str_parsed_runs = ""
90
+ runs = runs or []
91
+
92
+ def parse_runs():
93
+ parsed_runs = []
94
+ for run in runs:
95
+ if hasattr(run, "to_dict"):
96
+ run = run.to_dict()
97
+ if isinstance(run, dict):
98
+ parsed_run = {
99
+ "project": run["metadata"]["project"],
100
+ "name": run["metadata"]["name"],
101
+ "host": run["metadata"]["labels"]["host"],
102
+ "status": {"state": run["status"]["state"]},
103
+ }
104
+ if run["status"].get("error", None):
105
+ parsed_run["status"]["error"] = run["status"]["error"]
106
+ elif run["status"].get("results", None):
107
+ parsed_run["status"]["results"] = run["status"]["results"]
108
+ parsed_runs.append(parsed_run)
109
+ return str(parsed_runs)
110
+
111
+ if isinstance(override_body, dict):
112
+ for key, value in override_body.items():
113
+ if "{{ runs }}" or "{{runs}}" in value:
114
+ if not str_parsed_runs:
115
+ str_parsed_runs = parse_runs()
116
+ override_body[key] = value.replace(
117
+ "{{ runs }}", str_parsed_runs
118
+ ).replace("{{runs}}", str_parsed_runs)
119
+ return override_body
@@ -20,9 +20,9 @@ import traceback
20
20
  import typing
21
21
  from concurrent.futures import ThreadPoolExecutor
22
22
 
23
- import kfp
24
23
  import mlrun_pipelines.common.ops
25
24
  import mlrun_pipelines.models
25
+ import mlrun_pipelines.utils
26
26
 
27
27
  import mlrun.common.constants as mlrun_constants
28
28
  import mlrun.common.runtimes.constants
@@ -397,7 +397,7 @@ class NotificationPusher(_NotificationPusherBase):
397
397
  try:
398
398
  _run = db.list_runs(
399
399
  project=run.metadata.project,
400
- labels=f"mlrun_constants.MLRunInternalLabels.runner_pod={_step.node_name}",
400
+ labels=f"{mlrun_constants.MLRunInternalLabels.runner_pod}={_step.node_name}",
401
401
  )[0]
402
402
  except IndexError:
403
403
  _run = {
@@ -484,13 +484,7 @@ class NotificationPusher(_NotificationPusherBase):
484
484
  def _get_workflow_manifest(
485
485
  workflow_id: str,
486
486
  ) -> typing.Optional[mlrun_pipelines.models.PipelineManifest]:
487
- kfp_url = mlrun.mlconf.resolve_kfp_url(mlrun.mlconf.namespace)
488
- if not kfp_url:
489
- raise mlrun.errors.MLRunNotFoundError(
490
- "KubeFlow Pipelines is not configured"
491
- )
492
-
493
- kfp_client = kfp.Client(host=kfp_url)
487
+ kfp_client = mlrun_pipelines.utils.get_client(mlrun.mlconf)
494
488
 
495
489
  # arbitrary timeout of 5 seconds, the workflow should be done by now
496
490
  kfp_run = kfp_client.wait_for_run_completion(workflow_id, 5)
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "0cbcbb9417af7ac58072ad981672602728fee57e",
3
- "version": "1.7.0-rc22"
2
+ "git_commit": "71818c39b83a7e8c396aa2c37f1cd4f3e192dd2f",
3
+ "version": "1.7.0-rc28"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mlrun
3
- Version: 1.7.0rc22
3
+ Version: 1.7.0rc28
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -28,30 +28,30 @@ Requires-Dist: aiohttp-retry ~=2.8
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.9.17
31
+ Requires-Dist: nuclio-jupyter ~=0.10.0
32
32
  Requires-Dist: numpy <1.27.0,>=1.16.5
33
33
  Requires-Dist: pandas <2.2,>=1.2
34
34
  Requires-Dist: pyarrow <15,>=10.0
35
- Requires-Dist: pyyaml ~=5.1
35
+ Requires-Dist: pyyaml <7,>=5.4.1
36
36
  Requires-Dist: requests ~=2.31
37
37
  Requires-Dist: tabulate ~=0.8.6
38
38
  Requires-Dist: v3io ~=0.6.4
39
39
  Requires-Dist: pydantic <1.10.15,>=1.10.8
40
40
  Requires-Dist: mergedeep ~=1.3
41
- Requires-Dist: v3io-frames ~=0.10.12
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.4,>=2023.9.2
45
45
  Requires-Dist: v3iofs ~=0.1.17
46
- Requires-Dist: storey ~=1.7.17
46
+ Requires-Dist: storey ~=1.7.20
47
47
  Requires-Dist: inflection ~=0.5.0
48
48
  Requires-Dist: python-dotenv ~=0.17.0
49
49
  Requires-Dist: setuptools ~=69.1
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.0,~=0.1.1
54
- Requires-Dist: mlrun-pipelines-kfp-v1-8 >0.1.0,~=0.1.1
53
+ Requires-Dist: mlrun-pipelines-kfp-common ~=0.1.2
54
+ Requires-Dist: mlrun-pipelines-kfp-v1-8 ~=0.1.2
55
55
  Provides-Extra: alibaba-oss
56
56
  Requires-Dist: ossfs ==2023.12.0 ; extra == 'alibaba-oss'
57
57
  Requires-Dist: oss2 ==2.18.1 ; extra == 'alibaba-oss'
@@ -81,6 +81,7 @@ Requires-Dist: plotly <5.12.0,~=5.4 ; extra == 'all'
81
81
  Requires-Dist: pyopenssl >=23 ; extra == 'all'
82
82
  Requires-Dist: redis ~=4.3 ; extra == 'all'
83
83
  Requires-Dist: s3fs <2024.4,>=2023.9.2 ; extra == 'all'
84
+ Requires-Dist: snowflake-connector-python ~=3.7 ; extra == 'all'
84
85
  Requires-Dist: sqlalchemy ~=1.4 ; extra == 'all'
85
86
  Requires-Dist: taos-ws-py ~=0.3.2 ; extra == 'all'
86
87
  Provides-Extra: api
@@ -130,6 +131,7 @@ Requires-Dist: plotly <5.12.0,~=5.4 ; extra == 'complete'
130
131
  Requires-Dist: pyopenssl >=23 ; extra == 'complete'
131
132
  Requires-Dist: redis ~=4.3 ; extra == 'complete'
132
133
  Requires-Dist: s3fs <2024.4,>=2023.9.2 ; extra == 'complete'
134
+ Requires-Dist: snowflake-connector-python ~=3.7 ; extra == 'complete'
133
135
  Requires-Dist: sqlalchemy ~=1.4 ; extra == 'complete'
134
136
  Requires-Dist: taos-ws-py ~=0.3.2 ; extra == 'complete'
135
137
  Provides-Extra: complete-api
@@ -164,6 +166,7 @@ Requires-Dist: pymysql ~=1.0 ; extra == 'complete-api'
164
166
  Requires-Dist: pyopenssl >=23 ; extra == 'complete-api'
165
167
  Requires-Dist: redis ~=4.3 ; extra == 'complete-api'
166
168
  Requires-Dist: s3fs <2024.4,>=2023.9.2 ; extra == 'complete-api'
169
+ Requires-Dist: snowflake-connector-python ~=3.7 ; extra == 'complete-api'
167
170
  Requires-Dist: sqlalchemy ~=1.4 ; extra == 'complete-api'
168
171
  Requires-Dist: taos-ws-py ~=0.3.2 ; extra == 'complete-api'
169
172
  Requires-Dist: timelength ~=1.1 ; extra == 'complete-api'
@@ -196,6 +199,8 @@ Provides-Extra: s3
196
199
  Requires-Dist: boto3 <1.29.0,>=1.28.0 ; extra == 's3'
197
200
  Requires-Dist: aiobotocore <2.8,>=2.5.0 ; extra == 's3'
198
201
  Requires-Dist: s3fs <2024.4,>=2023.9.2 ; extra == 's3'
202
+ Provides-Extra: snowflake
203
+ Requires-Dist: snowflake-connector-python ~=3.7 ; extra == 'snowflake'
199
204
  Provides-Extra: sqlalchemy
200
205
  Requires-Dist: sqlalchemy ~=1.4 ; extra == 'sqlalchemy'
201
206
  Provides-Extra: tdengine