mlrun 1.7.0rc7__py3-none-any.whl → 1.7.0rc11__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 (91) hide show
  1. mlrun/__init__.py +1 -0
  2. mlrun/__main__.py +2 -0
  3. mlrun/artifacts/model.py +29 -25
  4. mlrun/common/schemas/__init__.py +4 -0
  5. mlrun/common/schemas/alert.py +122 -0
  6. mlrun/common/schemas/api_gateway.py +8 -1
  7. mlrun/common/schemas/auth.py +4 -0
  8. mlrun/common/schemas/client_spec.py +1 -0
  9. mlrun/common/schemas/hub.py +7 -9
  10. mlrun/common/schemas/model_monitoring/constants.py +4 -2
  11. mlrun/{datastore/helpers.py → common/schemas/pagination.py} +11 -3
  12. mlrun/common/schemas/project.py +15 -10
  13. mlrun/config.py +35 -13
  14. mlrun/datastore/__init__.py +3 -7
  15. mlrun/datastore/base.py +6 -5
  16. mlrun/datastore/datastore_profile.py +19 -1
  17. mlrun/datastore/snowflake_utils.py +43 -0
  18. mlrun/datastore/sources.py +18 -30
  19. mlrun/datastore/targets.py +140 -12
  20. mlrun/datastore/utils.py +10 -5
  21. mlrun/datastore/v3io.py +27 -50
  22. mlrun/db/base.py +88 -2
  23. mlrun/db/httpdb.py +314 -41
  24. mlrun/db/nopdb.py +142 -0
  25. mlrun/execution.py +21 -14
  26. mlrun/feature_store/api.py +9 -5
  27. mlrun/feature_store/feature_set.py +39 -23
  28. mlrun/feature_store/feature_vector.py +2 -1
  29. mlrun/feature_store/retrieval/spark_merger.py +27 -23
  30. mlrun/feature_store/steps.py +30 -19
  31. mlrun/features.py +4 -13
  32. mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
  33. mlrun/frameworks/lgbm/__init__.py +1 -1
  34. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  35. mlrun/frameworks/lgbm/model_handler.py +1 -1
  36. mlrun/frameworks/pytorch/__init__.py +2 -2
  37. mlrun/frameworks/sklearn/__init__.py +1 -1
  38. mlrun/frameworks/tf_keras/__init__.py +1 -1
  39. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  40. mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
  41. mlrun/frameworks/xgboost/__init__.py +1 -1
  42. mlrun/kfpops.py +2 -5
  43. mlrun/launcher/base.py +1 -1
  44. mlrun/launcher/client.py +2 -2
  45. mlrun/model.py +2 -2
  46. mlrun/model_monitoring/application.py +11 -2
  47. mlrun/model_monitoring/applications/histogram_data_drift.py +3 -3
  48. mlrun/model_monitoring/controller.py +2 -3
  49. mlrun/model_monitoring/helpers.py +3 -1
  50. mlrun/model_monitoring/stream_processing.py +0 -1
  51. mlrun/model_monitoring/writer.py +32 -0
  52. mlrun/package/packagers_manager.py +1 -0
  53. mlrun/platforms/__init__.py +1 -1
  54. mlrun/platforms/other.py +1 -1
  55. mlrun/projects/operations.py +11 -4
  56. mlrun/projects/pipelines.py +1 -1
  57. mlrun/projects/project.py +180 -73
  58. mlrun/run.py +77 -41
  59. mlrun/runtimes/__init__.py +16 -0
  60. mlrun/runtimes/base.py +4 -1
  61. mlrun/runtimes/kubejob.py +26 -121
  62. mlrun/runtimes/mpijob/abstract.py +8 -8
  63. mlrun/runtimes/nuclio/api_gateway.py +58 -8
  64. mlrun/runtimes/nuclio/application/application.py +79 -1
  65. mlrun/runtimes/nuclio/application/reverse_proxy.go +9 -1
  66. mlrun/runtimes/nuclio/function.py +20 -13
  67. mlrun/runtimes/nuclio/serving.py +11 -10
  68. mlrun/runtimes/pod.py +148 -3
  69. mlrun/runtimes/utils.py +0 -28
  70. mlrun/secrets.py +6 -2
  71. mlrun/serving/remote.py +2 -3
  72. mlrun/serving/routers.py +7 -4
  73. mlrun/serving/server.py +1 -1
  74. mlrun/serving/states.py +14 -38
  75. mlrun/serving/v2_serving.py +8 -7
  76. mlrun/utils/helpers.py +1 -1
  77. mlrun/utils/http.py +1 -1
  78. mlrun/utils/notifications/notification/base.py +12 -0
  79. mlrun/utils/notifications/notification/console.py +2 -0
  80. mlrun/utils/notifications/notification/git.py +3 -1
  81. mlrun/utils/notifications/notification/ipython.py +2 -0
  82. mlrun/utils/notifications/notification/slack.py +41 -13
  83. mlrun/utils/notifications/notification/webhook.py +11 -1
  84. mlrun/utils/retryer.py +3 -2
  85. mlrun/utils/version/version.json +2 -2
  86. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/METADATA +15 -15
  87. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/RECORD +91 -89
  88. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/LICENSE +0 -0
  89. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/WHEEL +0 -0
  90. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/entry_points.txt +0 -0
  91. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc11.dist-info}/top_level.txt +0 -0
mlrun/__init__.py CHANGED
@@ -97,6 +97,7 @@ def set_environment(
97
97
  example::
98
98
 
99
99
  from os import path
100
+
100
101
  project_name, artifact_path = set_environment()
101
102
  set_environment("http://localhost:8080", artifact_path="./")
102
103
  set_environment(env_file="mlrun.env")
mlrun/__main__.py CHANGED
@@ -505,6 +505,8 @@ def build(
505
505
  if kfp:
506
506
  print("Runtime:")
507
507
  pprint(runtime)
508
+ # use kind = "job" by default if not specified
509
+ runtime.setdefault("kind", "job")
508
510
  func = new_function(runtime=runtime)
509
511
 
510
512
  elif func_url:
mlrun/artifacts/model.py CHANGED
@@ -11,9 +11,10 @@
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
15
  import tempfile
15
16
  from os import path
16
- from typing import Any
17
+ from typing import Any, Optional
17
18
 
18
19
  import pandas as pd
19
20
  import yaml
@@ -69,8 +70,8 @@ class ModelArtifactSpec(ArtifactSpec):
69
70
  model_file=None,
70
71
  metrics=None,
71
72
  paraemeters=None,
72
- inputs: list[Feature] = None,
73
- outputs: list[Feature] = None,
73
+ inputs: Optional[list[Feature]] = None,
74
+ outputs: Optional[list[Feature]] = None,
74
75
  framework=None,
75
76
  algorithm=None,
76
77
  feature_vector=None,
@@ -92,8 +93,8 @@ class ModelArtifactSpec(ArtifactSpec):
92
93
  self.model_file = model_file
93
94
  self.metrics = metrics or {}
94
95
  self.parameters = paraemeters or {}
95
- self.inputs: list[Feature] = inputs or []
96
- self.outputs: list[Feature] = outputs or []
96
+ self.inputs = inputs or []
97
+ self.outputs = outputs or []
97
98
  self.framework = framework
98
99
  self.algorithm = algorithm
99
100
  self.feature_vector = feature_vector
@@ -102,21 +103,21 @@ class ModelArtifactSpec(ArtifactSpec):
102
103
  self.model_target_file = model_target_file
103
104
 
104
105
  @property
105
- def inputs(self) -> list[Feature]:
106
+ def inputs(self) -> ObjectList:
106
107
  """input feature list"""
107
108
  return self._inputs
108
109
 
109
110
  @inputs.setter
110
- def inputs(self, inputs: list[Feature]):
111
+ def inputs(self, inputs: list[Feature]) -> None:
111
112
  self._inputs = ObjectList.from_list(Feature, inputs)
112
113
 
113
114
  @property
114
- def outputs(self) -> list[Feature]:
115
+ def outputs(self) -> ObjectList:
115
116
  """output feature list"""
116
117
  return self._outputs
117
118
 
118
119
  @outputs.setter
119
- def outputs(self, outputs: list[Feature]):
120
+ def outputs(self, outputs: list[Feature]) -> None:
120
121
  self._outputs = ObjectList.from_list(Feature, outputs)
121
122
 
122
123
 
@@ -176,22 +177,22 @@ class ModelArtifact(Artifact):
176
177
  self._spec = self._verify_dict(spec, "spec", ModelArtifactSpec)
177
178
 
178
179
  @property
179
- def inputs(self) -> list[Feature]:
180
+ def inputs(self) -> ObjectList:
180
181
  """input feature list"""
181
182
  return self.spec.inputs
182
183
 
183
184
  @inputs.setter
184
- def inputs(self, inputs: list[Feature]):
185
+ def inputs(self, inputs: list[Feature]) -> None:
185
186
  """input feature list"""
186
187
  self.spec.inputs = inputs
187
188
 
188
189
  @property
189
- def outputs(self) -> list[Feature]:
190
+ def outputs(self) -> ObjectList:
190
191
  """input feature list"""
191
192
  return self.spec.outputs
192
193
 
193
194
  @outputs.setter
194
- def outputs(self, outputs: list[Feature]):
195
+ def outputs(self, outputs: list[Feature]) -> None:
195
196
  """input feature list"""
196
197
  self.spec.outputs = outputs
197
198
 
@@ -445,14 +446,14 @@ class LegacyModelArtifact(LegacyArtifact):
445
446
  **kwargs,
446
447
  ):
447
448
  super().__init__(key, body, format=format, target_path=target_path, **kwargs)
448
- self._inputs: ObjectList = None
449
- self._outputs: ObjectList = None
449
+ self._inputs: Optional[ObjectList] = None
450
+ self._outputs: Optional[ObjectList] = None
450
451
 
451
452
  self.model_file = model_file
452
453
  self.parameters = parameters or {}
453
454
  self.metrics = metrics or {}
454
- self.inputs: list[Feature] = inputs or []
455
- self.outputs: list[Feature] = outputs or []
455
+ self.inputs = inputs or []
456
+ self.outputs = outputs or []
456
457
  self.extra_data = extra_data or {}
457
458
  self.framework = framework
458
459
  self.algorithm = algorithm
@@ -462,21 +463,21 @@ class LegacyModelArtifact(LegacyArtifact):
462
463
  self.model_target_file = model_target_file
463
464
 
464
465
  @property
465
- def inputs(self) -> list[Feature]:
466
+ def inputs(self) -> Optional[ObjectList]:
466
467
  """input feature list"""
467
468
  return self._inputs
468
469
 
469
470
  @inputs.setter
470
- def inputs(self, inputs: list[Feature]):
471
+ def inputs(self, inputs: list[Feature]) -> None:
471
472
  self._inputs = ObjectList.from_list(Feature, inputs)
472
473
 
473
474
  @property
474
- def outputs(self) -> list[Feature]:
475
+ def outputs(self) -> Optional[ObjectList]:
475
476
  """output feature list"""
476
477
  return self._outputs
477
478
 
478
479
  @outputs.setter
479
- def outputs(self, outputs: list[Feature]):
480
+ def outputs(self, outputs: list[Feature]) -> None:
480
481
  self._outputs = ObjectList.from_list(Feature, outputs)
481
482
 
482
483
  def infer_from_df(self, df, label_columns=None, with_stats=True, num_bins=None):
@@ -552,9 +553,9 @@ def get_model(model_dir, suffix=""):
552
553
 
553
554
  example::
554
555
 
555
- model_file, model_artifact, extra_data = get_model(models_path, suffix='.pkl')
556
+ model_file, model_artifact, extra_data = get_model(models_path, suffix=".pkl")
556
557
  model = load(open(model_file, "rb"))
557
- categories = extra_data['categories'].as_df()
558
+ categories = extra_data["categories"].as_df()
558
559
 
559
560
  :param model_dir: model dir or artifact path (store://..) or DataItem
560
561
  :param suffix: model filename suffix (when using a dir)
@@ -663,8 +664,11 @@ def update_model(
663
664
 
664
665
  example::
665
666
 
666
- update_model(model_path, metrics={'speed': 100},
667
- extra_data={'my_data': b'some text', 'file': 's3://mybucket/..'})
667
+ update_model(
668
+ model_path,
669
+ metrics={"speed": 100},
670
+ extra_data={"my_data": b"some text", "file": "s3://mybucket/.."},
671
+ )
668
672
 
669
673
  :param model_artifact: model artifact object or path (store://..) or DataItem
670
674
  :param parameters: parameters dict
@@ -14,6 +14,7 @@
14
14
  #
15
15
  # flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
16
16
 
17
+ from .alert import AlertActiveState, AlertConfig, Event
17
18
  from .api_gateway import (
18
19
  APIGateway,
19
20
  APIGatewayAuthenticationMode,
@@ -21,6 +22,7 @@ from .api_gateway import (
21
22
  APIGatewayMetadata,
22
23
  APIGatewaysOutput,
23
24
  APIGatewaySpec,
25
+ APIGatewayState,
24
26
  APIGatewayStatus,
25
27
  APIGatewayUpstream,
26
28
  )
@@ -151,12 +153,14 @@ from .notification import (
151
153
  SetNotificationRequest,
152
154
  )
153
155
  from .object import ObjectKind, ObjectMetadata, ObjectSpec, ObjectStatus
156
+ from .pagination import PaginationInfo
154
157
  from .pipeline import PipelinesFormat, PipelinesOutput, PipelinesPagination
155
158
  from .project import (
156
159
  IguazioProject,
157
160
  Project,
158
161
  ProjectDesiredState,
159
162
  ProjectMetadata,
163
+ ProjectOutput,
160
164
  ProjectOwner,
161
165
  ProjectsFormat,
162
166
  ProjectsOutput,
@@ -0,0 +1,122 @@
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
+ #
15
+ from datetime import datetime
16
+ from typing import Annotated, Optional, Union
17
+
18
+ import pydantic
19
+
20
+ from mlrun.common.schemas.notification import Notification
21
+ from mlrun.common.types import StrEnum
22
+
23
+
24
+ class EventEntityKind(StrEnum):
25
+ MODEL = "model"
26
+ JOB = "job"
27
+
28
+
29
+ class EventEntity(pydantic.BaseModel):
30
+ kind: EventEntityKind
31
+ project: str
32
+ id: str
33
+
34
+
35
+ class EventKind(StrEnum):
36
+ DRIFT_DETECTED = "drift_detected"
37
+ DRIFT_SUSPECTED = "drift_suspected"
38
+ FAILED = "failed"
39
+
40
+
41
+ _event_kind_entity_map = {
42
+ EventKind.DRIFT_SUSPECTED: [EventEntityKind.MODEL],
43
+ EventKind.DRIFT_DETECTED: [EventEntityKind.MODEL],
44
+ EventKind.FAILED: [EventEntityKind.JOB],
45
+ }
46
+
47
+
48
+ class Event(pydantic.BaseModel):
49
+ kind: EventKind
50
+ timestamp: Union[str, datetime] = None # occurrence time
51
+ entity: EventEntity
52
+ value: Optional[Union[float, str]] = None
53
+
54
+ def is_valid(self):
55
+ return self.entity.kind in _event_kind_entity_map[self.kind]
56
+
57
+
58
+ class AlertActiveState(StrEnum):
59
+ ACTIVE = "active"
60
+ INACTIVE = "inactive"
61
+
62
+
63
+ class AlertSeverity(StrEnum):
64
+ LOW = "low"
65
+ MEDIUM = "medium"
66
+ HIGH = "high"
67
+
68
+
69
+ # what should trigger the alert. must be either event (at least 1), or prometheus query
70
+ class AlertTrigger(pydantic.BaseModel):
71
+ events: list[EventKind] = []
72
+ prometheus_alert: str = None
73
+
74
+
75
+ class AlertCriteria(pydantic.BaseModel):
76
+ count: Annotated[
77
+ int,
78
+ pydantic.Field(
79
+ description="Number of events to wait until notification is sent"
80
+ ),
81
+ ] = 0
82
+ period: Annotated[
83
+ str,
84
+ pydantic.Field(
85
+ description="Time period during which event occurred. e.g. 1d, 3h, 5m, 15s"
86
+ ),
87
+ ] = None
88
+
89
+
90
+ class ResetPolicy(StrEnum):
91
+ MANUAL = "manual"
92
+ AUTO = "auto"
93
+
94
+
95
+ class AlertConfig(pydantic.BaseModel):
96
+ project: str
97
+ id: int = None
98
+ name: str
99
+ description: Optional[str] = ""
100
+ summary: Annotated[
101
+ str,
102
+ pydantic.Field(
103
+ description=(
104
+ "String to be sent in the notifications generated."
105
+ "e.g. 'Model {{ $project }}/{{ $entity }} is drifting.'"
106
+ )
107
+ ),
108
+ ]
109
+ created: Union[str, datetime] = None
110
+ severity: AlertSeverity
111
+ entity: EventEntity
112
+ trigger: AlertTrigger
113
+ criteria: Optional[AlertCriteria]
114
+ reset_policy: ResetPolicy = ResetPolicy.MANUAL
115
+ notifications: pydantic.conlist(Notification, min_items=1)
116
+ state: AlertActiveState = AlertActiveState.INACTIVE
117
+ count: Optional[int] = 0
118
+
119
+
120
+ class AlertsModes(StrEnum):
121
+ enabled = "enabled"
122
+ disabled = "disabled"
@@ -36,6 +36,13 @@ class APIGatewayAuthenticationMode(mlrun.common.types.StrEnum):
36
36
  )
37
37
 
38
38
 
39
+ class APIGatewayState(mlrun.common.types.StrEnum):
40
+ none = ""
41
+ ready = "ready"
42
+ error = "error"
43
+ waiting_for_provisioning = "waitingForProvisioning"
44
+
45
+
39
46
  class _APIGatewayBaseModel(pydantic.BaseModel):
40
47
  class Config:
41
48
  extra = pydantic.Extra.allow
@@ -72,7 +79,7 @@ class APIGatewaySpec(_APIGatewayBaseModel):
72
79
 
73
80
  class APIGatewayStatus(_APIGatewayBaseModel):
74
81
  name: Optional[str]
75
- state: Optional[str]
82
+ state: Optional[APIGatewayState]
76
83
 
77
84
 
78
85
  class APIGateway(_APIGatewayBaseModel):
@@ -58,6 +58,8 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
58
58
  pipeline = "pipeline"
59
59
  hub_source = "hub-source"
60
60
  workflow = "workflow"
61
+ alert = "alert"
62
+ event = "event"
61
63
  datastore_profile = "datastore-profile"
62
64
  api_gateway = "api-gateway"
63
65
 
@@ -83,6 +85,8 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
83
85
  AuthorizationResourceTypes.schedule: "/projects/{project_name}/schedules/{resource_name}",
84
86
  AuthorizationResourceTypes.secret: "/projects/{project_name}/secrets/{resource_name}",
85
87
  AuthorizationResourceTypes.run: "/projects/{project_name}/runs/{resource_name}",
88
+ AuthorizationResourceTypes.event: "/projects/{project_name}/events/{resource_name}",
89
+ AuthorizationResourceTypes.alert: "/projects/{project_name}/alerts/{resource_name}",
86
90
  # runtime resource doesn't have an identifier, we don't need any auth granularity behind project level
87
91
  AuthorizationResourceTypes.runtime_resource: "/projects/{project_name}/runtime-resources",
88
92
  AuthorizationResourceTypes.model_endpoint: "/projects/{project_name}/model-endpoints/{resource_name}",
@@ -66,3 +66,4 @@ class ClientSpec(pydantic.BaseModel):
66
66
  logs: typing.Optional[dict]
67
67
  packagers: typing.Optional[dict]
68
68
  external_platform_tracking: typing.Optional[dict]
69
+ alerts_mode: typing.Optional[str]
@@ -59,28 +59,26 @@ class HubSource(BaseModel):
59
59
  return f"{self.spec.path}/{self.spec.object_type}/{self.spec.channel}/{relative_path}"
60
60
 
61
61
  def get_catalog_uri(self):
62
- return self.get_full_uri(mlrun.config.config.hub.catalog_filename)
62
+ return self.get_full_uri(mlrun.mlconf.hub.catalog_filename)
63
63
 
64
64
  @classmethod
65
65
  def generate_default_source(cls):
66
- if not mlrun.config.config.hub.default_source.create:
66
+ if not mlrun.mlconf.hub.default_source.create:
67
67
  return None
68
68
 
69
69
  now = datetime.now(timezone.utc)
70
70
  hub_metadata = HubObjectMetadata(
71
- name=mlrun.config.config.hub.default_source.name,
72
- description=mlrun.config.config.hub.default_source.description,
71
+ name=mlrun.mlconf.hub.default_source.name,
72
+ description=mlrun.mlconf.hub.default_source.description,
73
73
  created=now,
74
74
  updated=now,
75
75
  )
76
76
  return cls(
77
77
  metadata=hub_metadata,
78
78
  spec=HubSourceSpec(
79
- path=mlrun.config.config.hub.default_source.url,
80
- channel=mlrun.config.config.hub.default_source.channel,
81
- object_type=HubSourceType(
82
- mlrun.config.config.hub.default_source.object_type
83
- ),
79
+ path=mlrun.mlconf.hub.default_source.url,
80
+ channel=mlrun.mlconf.hub.default_source.channel,
81
+ object_type=HubSourceType(mlrun.mlconf.hub.default_source.object_type),
84
82
  ),
85
83
  status=ObjectStatus(state="created"),
86
84
  )
@@ -151,7 +151,7 @@ class ProjectSecretKeys:
151
151
  ENDPOINT_STORE_CONNECTION = "MODEL_MONITORING_ENDPOINT_STORE_CONNECTION"
152
152
  ACCESS_KEY = "MODEL_MONITORING_ACCESS_KEY"
153
153
  PIPELINES_ACCESS_KEY = "MODEL_MONITORING_PIPELINES_ACCESS_KEY"
154
- KAFKA_BOOTSTRAP_SERVERS = "KAFKA_BOOTSTRAP_SERVERS"
154
+ KAFKA_BROKERS = "KAFKA_BROKERS"
155
155
  STREAM_PATH = "STREAM_PATH"
156
156
 
157
157
 
@@ -308,4 +308,6 @@ class ControllerPolicy:
308
308
  BASE_PERIOD = "base_period"
309
309
 
310
310
 
311
- MLRUN_HISTOGRAM_DATA_DRIFT_APP_NAME = "histogram-data-drift"
311
+ class HistogramDataDriftApplicationConstants:
312
+ NAME = "histogram-data-drift"
313
+ GENERAL_RESULT_NAME = "general_drift"
@@ -11,8 +11,16 @@
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
- #
15
14
 
15
+ import typing
16
+
17
+ import pydantic
18
+
19
+
20
+ class PaginationInfo(pydantic.BaseModel):
21
+ class Config:
22
+ allow_population_by_field_name = True
16
23
 
17
- ONE_GB = 1024 * 1024 * 1024
18
- ONE_MB = 1024 * 1024
24
+ page: typing.Optional[int]
25
+ page_size: typing.Optional[int] = pydantic.Field(alias="page-size")
26
+ page_token: typing.Optional[str] = pydantic.Field(alias="page-token")
@@ -120,17 +120,22 @@ class IguazioProject(pydantic.BaseModel):
120
120
  data: dict
121
121
 
122
122
 
123
+ # The format query param controls the project type used:
124
+ # full - Project
125
+ # name_only - str
126
+ # summary - ProjectSummary
127
+ # leader - currently only IguazioProject supported
128
+ # The way pydantic handles typing.Union is that it takes the object and tries to coerce it to be the types of the
129
+ # union by the definition order. Therefore we can't currently add generic dict for all leader formats, but we need
130
+ # to add a specific classes for them. it's frustrating but couldn't find other workaround, see:
131
+ # https://github.com/samuelcolvin/pydantic/issues/1423, https://github.com/samuelcolvin/pydantic/issues/619
132
+ ProjectOutput = typing.TypeVar(
133
+ "ProjectOutput", Project, str, ProjectSummary, IguazioProject
134
+ )
135
+
136
+
123
137
  class ProjectsOutput(pydantic.BaseModel):
124
- # The format query param controls the project type used:
125
- # full - Project
126
- # name_only - str
127
- # summary - ProjectSummary
128
- # leader - currently only IguazioProject supported
129
- # The way pydantic handles typing.Union is that it takes the object and tries to coerce it to be the types of the
130
- # union by the definition order. Therefore we can't currently add generic dict for all leader formats, but we need
131
- # to add a specific classes for them. it's frustrating but couldn't find other workaround, see:
132
- # https://github.com/samuelcolvin/pydantic/issues/1423, https://github.com/samuelcolvin/pydantic/issues/619
133
- projects: list[typing.Union[Project, str, ProjectSummary, IguazioProject]]
138
+ projects: list[ProjectOutput]
134
139
 
135
140
 
136
141
  class ProjectSummariesOutput(pydantic.BaseModel):
mlrun/config.py CHANGED
@@ -240,6 +240,7 @@ default_config = {
240
240
  "remote": "mlrun/mlrun",
241
241
  "dask": "mlrun/ml-base",
242
242
  "mpijob": "mlrun/mlrun",
243
+ "application": "python:3.9-slim",
243
244
  },
244
245
  # see enrich_function_preemption_spec for more info,
245
246
  # and mlrun.common.schemas.function.PreemptionModes for available options
@@ -481,10 +482,13 @@ default_config = {
481
482
  # if set to true, will log a warning for trying to use run db functionality while in nop db mode
482
483
  "verbose": True,
483
484
  },
484
- "pagination_cache": {
485
- "interval": 60,
486
- "ttl": 3600,
487
- "max_size": 10000,
485
+ "pagination": {
486
+ "default_page_size": 20,
487
+ "pagination_cache": {
488
+ "interval": 60,
489
+ "ttl": 3600,
490
+ "max_size": 10000,
491
+ },
488
492
  },
489
493
  },
490
494
  "model_endpoint_monitoring": {
@@ -544,10 +548,11 @@ default_config = {
544
548
  },
545
549
  "feature_store": {
546
550
  "data_prefixes": {
547
- "default": "v3io:///projects/{project}/FeatureStore/{name}/{kind}",
548
- "nosql": "v3io:///projects/{project}/FeatureStore/{name}/{kind}",
551
+ "default": "v3io:///projects/{project}/FeatureStore/{name}/nosql",
552
+ "nosql": "v3io:///projects/{project}/FeatureStore/{name}/nosql",
549
553
  # "authority" is optional and generalizes [userinfo "@"] host [":" port]
550
- "redisnosql": "redis://{authority}/projects/{project}/FeatureStore/{name}/{kind}",
554
+ "redisnosql": "redis://{authority}/projects/{project}/FeatureStore/{name}/nosql",
555
+ "dsnosql": "ds://{ds_profile_name}/projects/{project}/FeatureStore/{name}/nosql",
551
556
  },
552
557
  "default_targets": "parquet,nosql",
553
558
  "default_job_image": "mlrun/mlrun",
@@ -683,6 +688,10 @@ default_config = {
683
688
  "access_key": "",
684
689
  },
685
690
  "grafana_url": "",
691
+ "alerts": {
692
+ # supported modes: "enabled", "disabled".
693
+ "mode": "disabled"
694
+ },
686
695
  }
687
696
 
688
697
  _is_running_as_api = None
@@ -1073,7 +1082,7 @@ class Config:
1073
1082
  target: str = "online",
1074
1083
  artifact_path: str = None,
1075
1084
  function_name: str = None,
1076
- ) -> str:
1085
+ ) -> typing.Union[str, list[str]]:
1077
1086
  """Get the full path from the configuration based on the provided project and kind.
1078
1087
 
1079
1088
  :param project: Project name.
@@ -1089,7 +1098,8 @@ class Config:
1089
1098
  relative artifact path will be taken from the global MLRun artifact path.
1090
1099
  :param function_name: Application name, None for model_monitoring_stream.
1091
1100
 
1092
- :return: Full configured path for the provided kind.
1101
+ :return: Full configured path for the provided kind. Can be either a single path
1102
+ or a list of paths in the case of the online model monitoring stream path.
1093
1103
  """
1094
1104
 
1095
1105
  if target != "offline":
@@ -1111,10 +1121,22 @@ class Config:
1111
1121
  if function_name is None
1112
1122
  else f"{kind}-{function_name.lower()}",
1113
1123
  )
1114
- return mlrun.mlconf.model_endpoint_monitoring.store_prefixes.default.format(
1115
- project=project,
1116
- kind=kind,
1117
- )
1124
+ elif kind == "stream": # return list for mlrun<1.6.3 BC
1125
+ return [
1126
+ mlrun.mlconf.model_endpoint_monitoring.store_prefixes.default.format(
1127
+ project=project,
1128
+ kind=kind,
1129
+ ), # old stream uri (pipelines) for BC ML-6043
1130
+ mlrun.mlconf.model_endpoint_monitoring.store_prefixes.user_space.format(
1131
+ project=project,
1132
+ kind=kind,
1133
+ ), # new stream uri (projects)
1134
+ ]
1135
+ else:
1136
+ return mlrun.mlconf.model_endpoint_monitoring.store_prefixes.default.format(
1137
+ project=project,
1138
+ kind=kind,
1139
+ )
1118
1140
 
1119
1141
  # Get the current offline path from the configuration
1120
1142
  file_path = mlrun.mlconf.model_endpoint_monitoring.offline_storage_path.format(
@@ -107,13 +107,9 @@ def get_stream_pusher(stream_path: str, **kwargs):
107
107
  :param stream_path: path/url of stream
108
108
  """
109
109
 
110
- if stream_path.startswith("kafka://") or "kafka_bootstrap_servers" in kwargs:
111
- topic, bootstrap_servers = parse_kafka_url(
112
- stream_path, kwargs.get("kafka_bootstrap_servers")
113
- )
114
- return KafkaOutputStream(
115
- topic, bootstrap_servers, kwargs.get("kafka_producer_options")
116
- )
110
+ if stream_path.startswith("kafka://") or "kafka_brokers" in kwargs:
111
+ topic, brokers = parse_kafka_url(stream_path, kwargs.get("kafka_brokers"))
112
+ return KafkaOutputStream(topic, brokers, kwargs.get("kafka_producer_options"))
117
113
  elif stream_path.startswith("http://") or stream_path.startswith("https://"):
118
114
  return HTTPOutputStream(stream_path=stream_path)
119
115
  elif "://" not in stream_path:
mlrun/datastore/base.py CHANGED
@@ -389,14 +389,15 @@ class DataItem:
389
389
 
390
390
 
391
391
  # reading run results using DataItem (run.artifact())
392
- train_run = train_iris_func.run(inputs={'dataset': dataset},
393
- params={'label_column': 'label'})
392
+ train_run = train_iris_func.run(
393
+ inputs={"dataset": dataset}, params={"label_column": "label"}
394
+ )
394
395
 
395
- train_run.artifact('confusion-matrix').show()
396
- test_set = train_run.artifact('test_set').as_df()
396
+ train_run.artifact("confusion-matrix").show()
397
+ test_set = train_run.artifact("test_set").as_df()
397
398
 
398
399
  # create and use DataItem from uri
399
- data = mlrun.get_dataitem('http://xyz/data.json').get()
400
+ data = mlrun.get_dataitem("http://xyz/data.json").get()
400
401
  """
401
402
 
402
403
  def __init__(
@@ -16,6 +16,7 @@ import ast
16
16
  import base64
17
17
  import json
18
18
  import typing
19
+ import warnings
19
20
  from urllib.parse import ParseResult, urlparse, urlunparse
20
21
 
21
22
  import pydantic
@@ -68,6 +69,9 @@ class TemporaryClientDatastoreProfiles(metaclass=mlrun.utils.singleton.Singleton
68
69
  def get(self, key):
69
70
  return self._data.get(key, None)
70
71
 
72
+ def remove(self, key):
73
+ self._data.pop(key, None)
74
+
71
75
 
72
76
  class DatastoreProfileBasic(DatastoreProfile):
73
77
  type: str = pydantic.Field("basic")
@@ -80,12 +84,22 @@ class DatastoreProfileKafkaTarget(DatastoreProfile):
80
84
  type: str = pydantic.Field("kafka_target")
81
85
  _private_attributes = "kwargs_private"
82
86
  bootstrap_servers: str
87
+ brokers: str
83
88
  topic: str
84
89
  kwargs_public: typing.Optional[dict]
85
90
  kwargs_private: typing.Optional[dict]
86
91
 
92
+ def __pydantic_post_init__(self):
93
+ if self.bootstrap_servers:
94
+ warnings.warn(
95
+ "'bootstrap_servers' parameter is deprecated in 1.7.0 and will be removed in 1.9.0, "
96
+ "use 'brokers' instead.",
97
+ # TODO: Remove this in 1.9.0
98
+ FutureWarning,
99
+ )
100
+
87
101
  def attributes(self):
88
- attributes = {"bootstrap_servers": self.bootstrap_servers}
102
+ attributes = {"brokers": self.brokers or self.bootstrap_servers}
89
103
  if self.kwargs_public:
90
104
  attributes = merge(attributes, self.kwargs_public)
91
105
  if self.kwargs_private:
@@ -460,3 +474,7 @@ def register_temporary_client_datastore_profile(profile: DatastoreProfile):
460
474
  It's beneficial for testing purposes.
461
475
  """
462
476
  TemporaryClientDatastoreProfiles().add(profile)
477
+
478
+
479
+ def remove_temporary_client_datastore_profile(profile_name: str):
480
+ TemporaryClientDatastoreProfiles().remove(profile_name)