mlrun 1.5.0rc12__py3-none-any.whl → 1.5.0rc13__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 (45) hide show
  1. mlrun/__main__.py +31 -2
  2. mlrun/api/api/endpoints/functions.py +110 -52
  3. mlrun/api/crud/model_monitoring/deployment.py +208 -38
  4. mlrun/api/crud/model_monitoring/helpers.py +19 -6
  5. mlrun/api/crud/model_monitoring/model_endpoints.py +14 -1
  6. mlrun/api/db/sqldb/db.py +3 -1
  7. mlrun/api/utils/builder.py +2 -4
  8. mlrun/common/model_monitoring/helpers.py +19 -5
  9. mlrun/common/schemas/model_monitoring/constants.py +69 -0
  10. mlrun/common/schemas/model_monitoring/model_endpoints.py +10 -0
  11. mlrun/config.py +30 -12
  12. mlrun/datastore/__init__.py +1 -0
  13. mlrun/datastore/sources.py +4 -30
  14. mlrun/datastore/targets.py +68 -31
  15. mlrun/db/httpdb.py +20 -6
  16. mlrun/feature_store/api.py +3 -31
  17. mlrun/feature_store/feature_vector.py +1 -1
  18. mlrun/feature_store/retrieval/base.py +8 -3
  19. mlrun/launcher/remote.py +3 -3
  20. mlrun/lists.py +11 -0
  21. mlrun/model_monitoring/__init__.py +0 -1
  22. mlrun/model_monitoring/api.py +1 -1
  23. mlrun/model_monitoring/application.py +313 -0
  24. mlrun/model_monitoring/batch_application.py +526 -0
  25. mlrun/model_monitoring/batch_application_handler.py +32 -0
  26. mlrun/model_monitoring/evidently_application.py +89 -0
  27. mlrun/model_monitoring/helpers.py +39 -3
  28. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +37 -0
  29. mlrun/model_monitoring/tracking_policy.py +4 -4
  30. mlrun/model_monitoring/writer.py +37 -0
  31. mlrun/projects/pipelines.py +38 -4
  32. mlrun/projects/project.py +257 -43
  33. mlrun/run.py +5 -2
  34. mlrun/runtimes/__init__.py +2 -0
  35. mlrun/runtimes/function.py +2 -1
  36. mlrun/utils/helpers.py +12 -0
  37. mlrun/utils/http.py +3 -0
  38. mlrun/utils/version/version.json +2 -2
  39. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/METADATA +5 -5
  40. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/RECORD +45 -40
  41. /mlrun/model_monitoring/{model_monitoring_batch.py → batch.py} +0 -0
  42. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/LICENSE +0 -0
  43. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/WHEEL +0 -0
  44. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/entry_points.txt +0 -0
  45. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/top_level.txt +0 -0
@@ -20,20 +20,56 @@ import mlrun.common.model_monitoring.helpers
20
20
  import mlrun.common.schemas
21
21
 
22
22
 
23
- def get_stream_path(project: str = None):
24
- """Get stream path from the project secret. If wasn't set, take it from the system configurations"""
23
+ def get_stream_path(project: str = None, application_name: str = None):
24
+ """
25
+ Get stream path from the project secret. If wasn't set, take it from the system configurations
26
+
27
+ :param project: Project name.
28
+ :param application_name: Application name, None for model_monitoring_stream.
29
+
30
+ :return: Monitoring stream path to the relevant application.
31
+ """
25
32
 
26
33
  stream_uri = mlrun.get_secret_or_env(
27
34
  mlrun.common.schemas.model_monitoring.ProjectSecretKeys.STREAM_PATH
35
+ if application_name is None
36
+ else ""
28
37
  ) or mlrun.mlconf.get_model_monitoring_file_target_path(
29
38
  project=project,
30
39
  kind=mlrun.common.schemas.model_monitoring.FileTargetKind.STREAM,
31
40
  target="online",
41
+ application_name=application_name,
32
42
  )
33
43
 
34
44
  return mlrun.common.model_monitoring.helpers.parse_monitoring_stream_path(
35
- stream_uri=stream_uri, project=project
45
+ stream_uri=stream_uri, project=project, application_name=application_name
46
+ )
47
+
48
+
49
+ def get_monitoring_parquet_path(
50
+ project: str,
51
+ kind: str = mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET,
52
+ ) -> str:
53
+ """Get model monitoring parquet target for the current project and kind. The parquet target path is based on the
54
+ project artifact path. If project artifact path is not defined, the parquet target path will be based on MLRun
55
+ artifact path.
56
+
57
+ :param project: Project name.
58
+ :param kind: indicate the kind of the parquet path, can be either stream_parquet or stream_controller_parquet
59
+
60
+ :return: Monitoring parquet target path.
61
+ """
62
+
63
+ project_obj = mlrun.get_or_create_project(name=project)
64
+ artifact_path = project_obj.spec.artifact_path
65
+ # Generate monitoring parquet path value
66
+ parquet_path = mlrun.mlconf.get_model_monitoring_file_target_path(
67
+ project=project,
68
+ kind=kind,
69
+ target="offline",
70
+ artifact_path=artifact_path,
36
71
  )
72
+ return parquet_path
37
73
 
38
74
 
39
75
  def get_connection_string(secret_provider: typing.Callable = None) -> str:
@@ -27,6 +27,12 @@ from mlrun.utils import logger
27
27
 
28
28
  from .model_endpoint_store import ModelEndpointStore
29
29
 
30
+ # Fields to encode before storing in the KV table or to decode after retrieving
31
+ fields_to_encode_decode = [
32
+ mlrun.common.schemas.model_monitoring.EventFieldType.FEATURE_STATS,
33
+ mlrun.common.schemas.model_monitoring.EventFieldType.CURRENT_STATS,
34
+ ]
35
+
30
36
 
31
37
  class KVModelEndpointStore(ModelEndpointStore):
32
38
  """
@@ -51,6 +57,11 @@ class KVModelEndpointStore(ModelEndpointStore):
51
57
  :param endpoint: model endpoint dictionary that will be written into the DB.
52
58
  """
53
59
 
60
+ for field in fields_to_encode_decode:
61
+ if field in endpoint:
62
+ # Encode to binary data
63
+ endpoint[field] = self._encode_field(endpoint[field])
64
+
54
65
  self.client.kv.put(
55
66
  container=self.container,
56
67
  table_path=self.path,
@@ -70,6 +81,11 @@ class KVModelEndpointStore(ModelEndpointStore):
70
81
 
71
82
  """
72
83
 
84
+ for field in fields_to_encode_decode:
85
+ if field in attributes:
86
+ # Encode to binary data
87
+ attributes[field] = self._encode_field(attributes[field])
88
+
73
89
  self.client.kv.update(
74
90
  container=self.container,
75
91
  table_path=self.path,
@@ -117,6 +133,11 @@ class KVModelEndpointStore(ModelEndpointStore):
117
133
  )
118
134
  endpoint = endpoint.output.item
119
135
 
136
+ for field in fields_to_encode_decode:
137
+ if field in endpoint:
138
+ # Decode binary data
139
+ endpoint[field] = self._decode_field(endpoint[field])
140
+
120
141
  if not endpoint:
121
142
  raise mlrun.errors.MLRunNotFoundError(f"Endpoint {endpoint_id} not found")
122
143
 
@@ -512,3 +533,19 @@ class KVModelEndpointStore(ModelEndpointStore):
512
533
  ] = endpoint[
513
534
  mlrun.common.schemas.model_monitoring.EventFieldType.ENDPOINT_ID
514
535
  ]
536
+
537
+ @staticmethod
538
+ def _encode_field(field: typing.Union[str, bytes]) -> bytes:
539
+ """Encode a provided field. Mainly used when storing data in the KV table."""
540
+
541
+ if isinstance(field, str):
542
+ return field.encode("ascii")
543
+ return field
544
+
545
+ @staticmethod
546
+ def _decode_field(field: typing.Union[str, bytes]) -> str:
547
+ """Decode a provided field. Mainly used when retrieving data from the KV table."""
548
+
549
+ if isinstance(field, bytes):
550
+ return field.decode()
551
+ return field
@@ -26,10 +26,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
26
26
  model monitoring stream.
27
27
  """
28
28
 
29
- _dict_fields = [
30
- "default_batch_image",
31
- "stream_image",
32
- ]
29
+ _dict_fields = ["default_batch_image", "stream_image", "application_batch"]
33
30
 
34
31
  def __init__(
35
32
  self,
@@ -38,6 +35,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
38
35
  ] = mlrun.common.schemas.schedule.ScheduleCronTrigger(minute="0", hour="*/1"),
39
36
  default_batch_image: str = "mlrun/mlrun",
40
37
  stream_image: str = "mlrun/mlrun",
38
+ application_batch: bool = False,
41
39
  ):
42
40
  """
43
41
  Initialize TrackingPolicy object.
@@ -50,6 +48,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
50
48
  is mlrun/mlrun.
51
49
  :param stream_image: The image of the model monitoring stream real-time function. By default,
52
50
  the image is mlrun/mlrun.
51
+ :param application_batch
53
52
  """
54
53
  if isinstance(default_batch_intervals, str):
55
54
  default_batch_intervals = (
@@ -60,6 +59,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
60
59
  self.default_batch_intervals = default_batch_intervals
61
60
  self.default_batch_image = default_batch_image
62
61
  self.stream_image = stream_image
62
+ self.application_batch = application_batch
63
63
 
64
64
  @classmethod
65
65
  def from_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
@@ -0,0 +1,37 @@
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
+ import mlrun.common.schemas
16
+ from mlrun.serving.utils import StepToDict
17
+
18
+
19
+ class ModelMonitoringWriter(StepToDict):
20
+ """DEMO WRITER TODO"""
21
+
22
+ kind = "monitoring_application_stream_pusher"
23
+
24
+ def __init__(self, name: str = None):
25
+ self.name = name or "king"
26
+
27
+ def do(self, event):
28
+
29
+ print(
30
+ f"endpoint_uid ={event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.ENDPOINT_ID]}, \n"
31
+ f"app_name = {event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.APPLICATION_NAME]}, \n"
32
+ f"schedule_time = {event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.SCHEDULE_TIME]}, \n"
33
+ f"result_name ={event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.RESULT_NAME]}, \n"
34
+ f"result_value ={event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.RESULT_VALUE]}, \n"
35
+ f"my_name = {self.name}."
36
+ )
37
+ return event
@@ -19,6 +19,7 @@ import tempfile
19
19
  import traceback
20
20
  import typing
21
21
  import uuid
22
+ import warnings
22
23
 
23
24
  import kfp.compiler
24
25
  from kfp import dsl
@@ -76,18 +77,28 @@ class WorkflowSpec(mlrun.model.ModelObj):
76
77
  args=None,
77
78
  name=None,
78
79
  handler=None,
80
+ # TODO: deprecated, remove in 1.6.0
81
+ ttl=None,
79
82
  args_schema: dict = None,
80
83
  schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
81
84
  cleanup_ttl: int = None,
82
85
  image: str = None,
83
86
  ):
87
+ if ttl:
88
+ warnings.warn(
89
+ "'ttl' is deprecated, use 'cleanup_ttl' instead. "
90
+ "This will be removed in 1.6.0",
91
+ # TODO: Remove this in 1.6.0
92
+ FutureWarning,
93
+ )
84
94
  self.engine = engine
85
95
  self.code = code
86
96
  self.path = path
87
97
  self.args = args
88
98
  self.name = name
89
99
  self.handler = handler
90
- self.cleanup_ttl = cleanup_ttl
100
+ self.ttl = cleanup_ttl or ttl
101
+ self.cleanup_ttl = cleanup_ttl or ttl
91
102
  self.args_schema = args_schema
92
103
  self.run_local = False
93
104
  self._tmp_path = None
@@ -550,7 +561,7 @@ class _KFPRunner(_PipelineRunner):
550
561
 
551
562
  conf = new_pipe_metadata(
552
563
  artifact_path=artifact_path,
553
- cleanup_ttl=workflow_spec.cleanup_ttl,
564
+ cleanup_ttl=workflow_spec.cleanup_ttl or workflow_spec.ttl,
554
565
  )
555
566
  compiler.Compiler().compile(pipeline, target, pipeline_conf=conf)
556
567
  workflow_spec.clear_tmp()
@@ -583,7 +594,7 @@ class _KFPRunner(_PipelineRunner):
583
594
  experiment=name or workflow_spec.name,
584
595
  namespace=namespace,
585
596
  artifact_path=artifact_path,
586
- cleanup_ttl=workflow_spec.cleanup_ttl,
597
+ cleanup_ttl=workflow_spec.cleanup_ttl or workflow_spec.ttl,
587
598
  )
588
599
  project.notifiers.push_pipeline_start_message(
589
600
  project.metadata.name,
@@ -764,6 +775,13 @@ class _RemoteRunner(_PipelineRunner):
764
775
  inner_engine = get_workflow_engine(workflow_spec.engine)
765
776
  run_db = mlrun.get_run_db()
766
777
  try:
778
+ logger.info(
779
+ "Submitting remote workflow",
780
+ workflow_engine=workflow_spec.engine,
781
+ schedule=workflow_spec.schedule,
782
+ project_name=project.name,
783
+ )
784
+
767
785
  workflow_response = run_db.submit_workflow(
768
786
  project=project.name,
769
787
  name=workflow_name,
@@ -776,6 +794,10 @@ class _RemoteRunner(_PipelineRunner):
776
794
  namespace=namespace,
777
795
  )
778
796
  if workflow_spec.schedule:
797
+ logger.info(
798
+ "Workflow scheduled successfully",
799
+ workflow_response=workflow_response,
800
+ )
779
801
  return
780
802
 
781
803
  # Getting workflow id from run:
@@ -883,6 +905,8 @@ def load_and_run(
883
905
  namespace: str = None,
884
906
  sync: bool = False,
885
907
  dirty: bool = False,
908
+ # TODO: deprecated, remove in 1.6.0
909
+ ttl: int = None,
886
910
  engine: str = None,
887
911
  local: bool = None,
888
912
  schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
@@ -910,6 +934,8 @@ def load_and_run(
910
934
  :param namespace: kubernetes namespace if other than default
911
935
  :param sync: force functions sync before run
912
936
  :param dirty: allow running the workflow when the git repo is dirty
937
+ :param ttl: pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
938
+ workflow and all its resources are deleted) (deprecated, use cleanup_ttl instead)
913
939
  :param engine: workflow engine running the workflow.
914
940
  supported values are 'kfp' (default) or 'local'
915
941
  :param local: run local pipeline with local functions (set local=True in function.run())
@@ -918,6 +944,14 @@ def load_and_run(
918
944
  workflow and all its resources are deleted)
919
945
  :param load_only: for just loading the project, inner use.
920
946
  """
947
+ if ttl:
948
+ warnings.warn(
949
+ "'ttl' is deprecated, use 'cleanup_ttl' instead. "
950
+ "This will be removed in 1.6.0",
951
+ # TODO: Remove this in 1.6.0
952
+ FutureWarning,
953
+ )
954
+
921
955
  try:
922
956
  project = mlrun.load_project(
923
957
  context=f"./{project_name}",
@@ -969,7 +1003,7 @@ def load_and_run(
969
1003
  sync=sync,
970
1004
  watch=False, # Required for fetching the workflow_id
971
1005
  dirty=dirty,
972
- cleanup_ttl=cleanup_ttl,
1006
+ cleanup_ttl=cleanup_ttl or ttl,
973
1007
  engine=engine,
974
1008
  local=local,
975
1009
  )