mlrun 1.8.0rc5__py3-none-any.whl → 1.8.0rc9__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 (74) hide show
  1. mlrun/__init__.py +1 -0
  2. mlrun/artifacts/__init__.py +1 -1
  3. mlrun/artifacts/base.py +21 -1
  4. mlrun/artifacts/document.py +62 -39
  5. mlrun/artifacts/manager.py +12 -5
  6. mlrun/common/constants.py +1 -0
  7. mlrun/common/model_monitoring/__init__.py +0 -2
  8. mlrun/common/model_monitoring/helpers.py +0 -28
  9. mlrun/common/schemas/__init__.py +2 -4
  10. mlrun/common/schemas/alert.py +77 -1
  11. mlrun/common/schemas/client_spec.py +0 -1
  12. mlrun/common/schemas/model_monitoring/__init__.py +0 -6
  13. mlrun/common/schemas/model_monitoring/constants.py +11 -9
  14. mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
  15. mlrun/common/schemas/notification.py +6 -0
  16. mlrun/common/schemas/project.py +3 -0
  17. mlrun/config.py +2 -3
  18. mlrun/datastore/datastore_profile.py +57 -17
  19. mlrun/datastore/sources.py +1 -2
  20. mlrun/datastore/store_resources.py +7 -2
  21. mlrun/datastore/vectorstore.py +99 -62
  22. mlrun/db/base.py +34 -20
  23. mlrun/db/httpdb.py +249 -163
  24. mlrun/db/nopdb.py +40 -17
  25. mlrun/execution.py +14 -7
  26. mlrun/feature_store/api.py +1 -0
  27. mlrun/model.py +3 -0
  28. mlrun/model_monitoring/__init__.py +3 -2
  29. mlrun/model_monitoring/api.py +64 -53
  30. mlrun/model_monitoring/applications/_application_steps.py +3 -1
  31. mlrun/model_monitoring/applications/base.py +115 -15
  32. mlrun/model_monitoring/applications/context.py +42 -24
  33. mlrun/model_monitoring/applications/histogram_data_drift.py +1 -1
  34. mlrun/model_monitoring/controller.py +43 -37
  35. mlrun/model_monitoring/db/__init__.py +0 -2
  36. mlrun/model_monitoring/db/tsdb/base.py +2 -1
  37. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
  38. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
  39. mlrun/model_monitoring/helpers.py +78 -66
  40. mlrun/model_monitoring/stream_processing.py +83 -270
  41. mlrun/model_monitoring/writer.py +1 -10
  42. mlrun/projects/pipelines.py +37 -1
  43. mlrun/projects/project.py +173 -70
  44. mlrun/run.py +40 -0
  45. mlrun/runtimes/nuclio/function.py +7 -6
  46. mlrun/runtimes/nuclio/serving.py +9 -4
  47. mlrun/serving/routers.py +158 -145
  48. mlrun/serving/server.py +6 -0
  49. mlrun/serving/states.py +21 -7
  50. mlrun/serving/v2_serving.py +94 -68
  51. mlrun/utils/helpers.py +23 -33
  52. mlrun/utils/notifications/notification/mail.py +17 -6
  53. mlrun/utils/notifications/notification_pusher.py +9 -5
  54. mlrun/utils/regex.py +8 -1
  55. mlrun/utils/version/version.json +2 -2
  56. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/METADATA +2 -2
  57. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/RECORD +61 -74
  58. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
  59. mlrun/model_monitoring/db/stores/__init__.py +0 -136
  60. mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
  61. mlrun/model_monitoring/db/stores/base/store.py +0 -154
  62. mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
  63. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
  64. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
  65. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
  66. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
  67. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
  68. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
  69. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
  70. mlrun/model_monitoring/model_endpoint.py +0 -120
  71. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/LICENSE +0 -0
  72. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/WHEEL +0 -0
  73. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/entry_points.txt +0 -0
  74. {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc9.dist-info}/top_level.txt +0 -0
@@ -21,10 +21,9 @@ import mlrun.artifacts
21
21
  import mlrun.common.model_monitoring.helpers
22
22
  import mlrun.common.schemas.model_monitoring
23
23
  import mlrun.model_monitoring
24
- from mlrun.errors import err_to_str
25
24
  from mlrun.utils import logger, now_date
26
25
 
27
- from ..common.helpers import parse_versioned_object_uri
26
+ from ..common.schemas.model_monitoring import ModelEndpointSchema
28
27
  from .server import GraphServer
29
28
  from .utils import StepToDict, _extract_input_data, _update_result_body
30
29
 
@@ -110,12 +109,6 @@ class V2ModelServer(StepToDict):
110
109
  self._result_path = result_path
111
110
  self._kwargs = kwargs # for to_dict()
112
111
  self._params = kwargs
113
- self._model_logger = (
114
- _ModelLogPusher(self, context)
115
- if context and context.stream.enabled
116
- else None
117
- )
118
-
119
112
  self.metrics = {}
120
113
  self.labels = {}
121
114
  self.model = None
@@ -125,6 +118,7 @@ class V2ModelServer(StepToDict):
125
118
  self._versioned_model_name = None
126
119
  self.model_endpoint_uid = None
127
120
  self.shard_by_endpoint = shard_by_endpoint
121
+ self._model_logger = None
128
122
 
129
123
  def _load_and_update_state(self):
130
124
  try:
@@ -157,6 +151,11 @@ class V2ModelServer(StepToDict):
157
151
  self.model_endpoint_uid = _init_endpoint_record(
158
152
  graph_server=server, model=self
159
153
  )
154
+ self._model_logger = (
155
+ _ModelLogPusher(self, self.context)
156
+ if self.context and self.context.stream.enabled
157
+ else None
158
+ )
160
159
 
161
160
  def get_param(self, key: str, default=None):
162
161
  """get param by key (specified in the model or the function)"""
@@ -198,13 +197,15 @@ class V2ModelServer(StepToDict):
198
197
  extra dataitems dictionary
199
198
 
200
199
  """
201
- model_file, self.model_spec, extra_dataitems = mlrun.artifacts.get_model(
202
- self.model_path, suffix
203
- )
204
- if self.model_spec and self.model_spec.parameters:
205
- for key, value in self.model_spec.parameters.items():
206
- self._params[key] = value
207
- return model_file, extra_dataitems
200
+ if self.model_path:
201
+ model_file, self.model_spec, extra_dataitems = mlrun.artifacts.get_model(
202
+ self.model_path, suffix
203
+ )
204
+ if self.model_spec and self.model_spec.parameters:
205
+ for key, value in self.model_spec.parameters.items():
206
+ self._params[key] = value
207
+ return model_file, extra_dataitems
208
+ return None, None
208
209
 
209
210
  def load(self):
210
211
  """model loading function, see also .get_model() method"""
@@ -474,7 +475,7 @@ class V2ModelServer(StepToDict):
474
475
 
475
476
 
476
477
  class _ModelLogPusher:
477
- def __init__(self, model, context, output_stream=None):
478
+ def __init__(self, model: V2ModelServer, context, output_stream=None):
478
479
  self.model = model
479
480
  self.verbose = context.verbose
480
481
  self.hostname = context.stream.hostname
@@ -496,6 +497,7 @@ class _ModelLogPusher:
496
497
  "version": self.model.version,
497
498
  "host": self.hostname,
498
499
  "function_uri": self.function_uri,
500
+ "endpoint_id": self.model.model_endpoint_uid,
499
501
  }
500
502
  if getattr(self.model, "labels", None):
501
503
  base_data["labels"] = self.model.labels
@@ -567,26 +569,24 @@ def _init_endpoint_record(
567
569
  """
568
570
 
569
571
  logger.info("Initializing endpoint records")
570
-
571
- # Generate required values for the model endpoint record
572
- try:
573
- # Getting project name from the function uri
574
- project, uri, tag, hash_key = parse_versioned_object_uri(
575
- graph_server.function_uri
576
- )
577
- except Exception as e:
578
- logger.error("Failed to parse function URI", exc=err_to_str(e))
579
- return None
580
-
581
- # Generating model endpoint ID based on function uri and model version
582
- uid = mlrun.common.model_monitoring.create_model_endpoint_uid(
583
- function_uri=graph_server.function_uri,
584
- versioned_model=model.versioned_model_name,
585
- ).uid
586
-
572
+ if not model.model_spec:
573
+ model.get_model()
574
+ if model.model_spec:
575
+ model_name = model.model_spec.metadata.key
576
+ model_uid = model.model_spec.metadata.uid
577
+ model_tag = model.model_spec.tag
578
+ model_labels = model.model_spec.labels # todo : check if we still need this
579
+ else:
580
+ model_name = None
581
+ model_uid = None
582
+ model_tag = None
583
+ model_labels = {}
587
584
  try:
588
585
  model_ep = mlrun.get_run_db().get_model_endpoint(
589
- project=project, endpoint_id=uid
586
+ project=graph_server.project,
587
+ name=model.name,
588
+ function_name=graph_server.function_name,
589
+ function_tag=graph_server.function_tag or "latest",
590
590
  )
591
591
  except mlrun.errors.MLRunNotFoundError:
592
592
  model_ep = None
@@ -596,62 +596,88 @@ def _init_endpoint_record(
596
596
  )
597
597
  return
598
598
 
599
- if model.context.server.track_models and not model_ep:
600
- logger.info("Creating a new model endpoint record", endpoint_id=uid)
601
- model_endpoint = mlrun.common.schemas.ModelEndpoint(
599
+ function = mlrun.get_run_db().get_function(
600
+ name=graph_server.function_name,
601
+ project=graph_server.project,
602
+ tag=graph_server.function_tag or "latest",
603
+ )
604
+ function_uid = function.get("metadata", {}).get("uid")
605
+ if not model_ep and model.context.server.track_models:
606
+ logger.info(
607
+ "Creating a new model endpoint record",
608
+ name=model.name,
609
+ project=graph_server.project,
610
+ function_name=graph_server.function_name,
611
+ function_tag=graph_server.function_tag or "latest",
612
+ function_uid=function_uid,
613
+ model_name=model_name,
614
+ model_uid=model_uid,
615
+ model_class=model.__class__.__name__,
616
+ model_tag=model_tag,
617
+ )
618
+ model_ep = mlrun.common.schemas.ModelEndpoint(
602
619
  metadata=mlrun.common.schemas.ModelEndpointMetadata(
603
- project=project, labels=model.labels, uid=uid
620
+ project=graph_server.project,
621
+ labels=model_labels,
622
+ name=model.name,
623
+ endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP,
604
624
  ),
605
625
  spec=mlrun.common.schemas.ModelEndpointSpec(
606
- function_uri=graph_server.function_uri,
607
- model=model.versioned_model_name,
626
+ function_name=graph_server.function_name,
627
+ function_uid=function_uid,
628
+ function_tag=graph_server.function_tag or "latest",
629
+ model_name=model_name,
630
+ model_uid=model_uid,
608
631
  model_class=model.__class__.__name__,
609
- model_uri=model.model_path,
610
- stream_path=model.context.stream.stream_uri,
611
- active=True,
612
- monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled,
613
632
  ),
614
633
  status=mlrun.common.schemas.ModelEndpointStatus(
615
- endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP
634
+ monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
635
+ if model.context.server.track_models
636
+ else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled,
616
637
  ),
617
638
  )
618
-
619
639
  db = mlrun.get_run_db()
620
- db.create_model_endpoint(
621
- project=project,
622
- endpoint_id=uid,
623
- model_endpoint=model_endpoint.dict(),
624
- )
640
+ model_ep = db.create_model_endpoint(model_endpoint=model_ep)
625
641
 
626
642
  elif model_ep:
627
643
  attributes = {}
628
- old_model_uri = model_ep.spec.model_uri
629
- mlrun.model_monitoring.helpers.enrich_model_endpoint_with_model_uri(
630
- model_endpoint=model_ep,
631
- model_obj=model.model_spec,
632
- )
633
- if model_ep.spec.model_uri != old_model_uri:
634
- attributes["model_uri"] = model_ep.spec.model_uri
644
+ if function_uid != model_ep.spec.function_uid:
645
+ attributes[ModelEndpointSchema.FUNCTION_UID] = function_uid
646
+ if model_name != model_ep.spec.model_name:
647
+ attributes[ModelEndpointSchema.MODEL_NAME] = model_name
648
+ if model_uid != model_ep.spec.model_uid:
649
+ attributes[ModelEndpointSchema.MODEL_UID] = model_uid
650
+ if model_tag != model_ep.spec.model_tag:
651
+ attributes[ModelEndpointSchema.MODEL_TAG] = model_tag
652
+ if model_labels != model_ep.metadata.labels:
653
+ attributes[ModelEndpointSchema.LABELS] = model_labels
654
+ if model.__class__.__name__ != model_ep.spec.model_class:
655
+ attributes[ModelEndpointSchema.MODEL_CLASS] = model.__class__.__name__
635
656
  if (
636
- model_ep.spec.monitoring_mode
657
+ model_ep.status.monitoring_mode
637
658
  == mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
638
659
  ) != model.context.server.track_models:
639
- attributes["monitoring_mode"] = (
660
+ attributes[ModelEndpointSchema.MONITORING_MODE] = (
640
661
  mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
641
662
  if model.context.server.track_models
642
663
  else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled
643
664
  )
644
665
  if attributes:
645
- db = mlrun.get_run_db()
646
- db.patch_model_endpoint(
647
- project=project,
648
- endpoint_id=uid,
649
- attributes=attributes,
650
- )
651
666
  logger.info(
652
667
  "Updating model endpoint attributes",
653
668
  attributes=attributes,
654
- endpoint_id=uid,
669
+ project=model_ep.metadata.project,
670
+ name=model_ep.metadata.name,
671
+ function_name=model_ep.spec.function_name,
655
672
  )
673
+ db = mlrun.get_run_db()
674
+ model_ep = db.patch_model_endpoint(
675
+ project=model_ep.metadata.project,
676
+ name=model_ep.metadata.name,
677
+ endpoint_id=model_ep.metadata.uid,
678
+ attributes=attributes,
679
+ )
680
+ else:
681
+ return None
656
682
 
657
- return uid
683
+ return model_ep.metadata.uid
mlrun/utils/helpers.py CHANGED
@@ -670,8 +670,8 @@ def dict_to_json(struct):
670
670
 
671
671
  def parse_artifact_uri(uri, default_project=""):
672
672
  """
673
- Parse artifact URI into project, key, tag, iter, tree
674
- URI format: [<project>/]<key>[#<iter>][:<tag>][@<tree>]
673
+ Parse artifact URI into project, key, tag, iter, tree, uid
674
+ URI format: [<project>/]<key>[#<iter>][:<tag>][@<tree>][^<uid>]
675
675
 
676
676
  :param uri: uri to parse
677
677
  :param default_project: default project name if not in URI
@@ -681,6 +681,7 @@ def parse_artifact_uri(uri, default_project=""):
681
681
  [2] = iteration
682
682
  [3] = tag
683
683
  [4] = tree
684
+ [5] = uid
684
685
  """
685
686
  uri_pattern = mlrun.utils.regex.artifact_uri_pattern
686
687
  match = re.match(uri_pattern, uri)
@@ -705,6 +706,7 @@ def parse_artifact_uri(uri, default_project=""):
705
706
  iteration,
706
707
  group_dict["tag"],
707
708
  group_dict["tree"],
709
+ group_dict["uid"],
708
710
  )
709
711
 
710
712
 
@@ -719,7 +721,9 @@ def generate_object_uri(project, name, tag=None, hash_key=None):
719
721
  return uri
720
722
 
721
723
 
722
- def generate_artifact_uri(project, key, tag=None, iter=None, tree=None):
724
+ def generate_artifact_uri(
725
+ project, key, tag=None, iter=None, tree=None, uid=None
726
+ ) -> str:
723
727
  artifact_uri = f"{project}/{key}"
724
728
  if iter is not None:
725
729
  artifact_uri = f"{artifact_uri}#{iter}"
@@ -727,6 +731,8 @@ def generate_artifact_uri(project, key, tag=None, iter=None, tree=None):
727
731
  artifact_uri = f"{artifact_uri}:{tag}"
728
732
  if tree is not None:
729
733
  artifact_uri = f"{artifact_uri}@{tree}"
734
+ if uid is not None:
735
+ artifact_uri = f"{artifact_uri}^{uid}"
730
736
  return artifact_uri
731
737
 
732
738
 
@@ -956,36 +962,6 @@ def fill_function_hash(function_dict, tag=""):
956
962
  return fill_object_hash(function_dict, "hash", tag)
957
963
 
958
964
 
959
- def fill_model_endpoint_hash(
960
- model_endpoint: mlrun.common.schemas.ModelEndpointV2,
961
- created_time: typing.Union[str, datetime],
962
- ) -> str:
963
- """
964
- Fill the model endpoint uid field in the model endpoint object and returns it.
965
- The uid is generated by hashing the following model endpoint fields:
966
- - name
967
- - model_tag
968
- - function_name
969
- - project
970
- - created_time
971
- """
972
-
973
- name = model_endpoint.metadata.name
974
- model_tag = model_endpoint.spec.model_tag
975
- function_name = model_endpoint.spec.function_name
976
- project = model_endpoint.metadata.project
977
- created_time = (
978
- created_time
979
- if isinstance(created_time, str)
980
- else created_time.isoformat(sep=" ", timespec="microseconds")
981
- )
982
-
983
- unique_string = f"{name}_{model_tag}_{function_name}_{project}_{created_time}"
984
- uid = hashlib.sha1(unique_string.encode("utf-8")).hexdigest()
985
- model_endpoint.metadata.uid = uid
986
- return uid
987
-
988
-
989
965
  def retry_until_successful(
990
966
  backoff: int, timeout: int, logger, verbose: bool, _function, *args, **kwargs
991
967
  ):
@@ -1886,3 +1862,17 @@ def run_with_retry(
1886
1862
  if attempt == retry_count:
1887
1863
  raise
1888
1864
  raise last_exception
1865
+
1866
+
1867
+ def join_urls(base_url: Optional[str], path: Optional[str]) -> str:
1868
+ """
1869
+ Joins a base URL with a path, ensuring proper handling of slashes.
1870
+
1871
+ :param base_url: The base URL (e.g., "http://example.com").
1872
+ :param path: The path to append to the base URL (e.g., "/path/to/resource").
1873
+
1874
+ :return: A unified URL with exactly one slash between base_url and path.
1875
+ """
1876
+ if base_url is None:
1877
+ base_url = ""
1878
+ return f"{base_url.rstrip('/')}/{path.lstrip('/')}" if path else base_url
@@ -13,7 +13,8 @@
13
13
  # limitations under the License.
14
14
  import re
15
15
  import typing
16
- from email.message import EmailMessage
16
+ from email.mime.multipart import MIMEMultipart
17
+ from email.mime.text import MIMEText
17
18
 
18
19
  import aiosmtplib
19
20
 
@@ -69,9 +70,19 @@ class MailNotification(base.NotificationBase):
69
70
  alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
70
71
  event_data: typing.Optional[mlrun.common.schemas.Event] = None,
71
72
  ):
72
- message = self.params.get("message", message)
73
- self.params.setdefault("subject", f"[{severity}] {message}")
74
- self.params.setdefault("body", message)
73
+ self.params["subject"] = f"[{severity}] {message}"
74
+ message_body_override = self.params.get("message_body_override", None)
75
+
76
+ runs_html = self._get_html(
77
+ message, severity, runs, custom_html, alert, event_data
78
+ )
79
+ self.params["body"] = runs_html
80
+
81
+ if message_body_override:
82
+ self.params["body"] = message_body_override.replace(
83
+ "{{ runs }}", runs_html
84
+ ).replace("{{runs}}", runs_html)
85
+
75
86
  await self._send_email(**self.params)
76
87
 
77
88
  @classmethod
@@ -146,11 +157,11 @@ class MailNotification(base.NotificationBase):
146
157
  **kwargs,
147
158
  ):
148
159
  # Create the email message
149
- message = EmailMessage()
160
+ message = MIMEMultipart("alternative")
150
161
  message["From"] = sender_address
151
162
  message["To"] = email_addresses
152
163
  message["Subject"] = subject
153
- message.set_content(body)
164
+ message.attach(MIMEText(body, "html"))
154
165
 
155
166
  # Send the email
156
167
  await aiosmtplib.send(
@@ -21,7 +21,7 @@ import typing
21
21
  from concurrent.futures import ThreadPoolExecutor
22
22
 
23
23
  import mlrun.common.constants as mlrun_constants
24
- import mlrun.common.runtimes.constants
24
+ import mlrun.common.runtimes.constants as runtimes_constants
25
25
  import mlrun.common.schemas
26
26
  import mlrun.config
27
27
  import mlrun.db.base
@@ -226,7 +226,7 @@ class NotificationPusher(_NotificationPusherBase):
226
226
  for when_state in when_states:
227
227
  if when_state == run_state:
228
228
  if (
229
- run_state == "completed"
229
+ run_state == runtimes_constants.RunStates.completed
230
230
  and evaluate_condition_in_separate_process(
231
231
  notification.condition,
232
232
  context={
@@ -234,7 +234,11 @@ class NotificationPusher(_NotificationPusherBase):
234
234
  "notification": notification.to_dict(),
235
235
  },
236
236
  )
237
- ) or run_state in ["error", "aborted"]:
237
+ ) or run_state in [
238
+ runtimes_constants.RunStates.error,
239
+ runtimes_constants.RunStates.aborted,
240
+ runtimes_constants.RunStates.running,
241
+ ]:
238
242
  return True
239
243
 
240
244
  return False
@@ -441,7 +445,7 @@ class NotificationPusher(_NotificationPusherBase):
441
445
  _run["step_kind"] = _step.step_type
442
446
  if _step.skipped:
443
447
  _run.setdefault("status", {})["state"] = (
444
- mlrun.common.runtimes.constants.RunStates.skipped
448
+ runtimes_constants.RunStates.skipped
445
449
  )
446
450
  steps.append(_run)
447
451
 
@@ -468,7 +472,7 @@ class NotificationPusher(_NotificationPusherBase):
468
472
  if _step.skipped:
469
473
  state = mlrun.common.schemas.FunctionState.skipped
470
474
  else:
471
- state = mlrun.common.runtimes.constants.PodPhases.pod_phase_to_run_state(
475
+ state = runtimes_constants.PodPhases.pod_phase_to_run_state(
472
476
  pod_phase
473
477
  )
474
478
  function["status"] = {"state": state}
mlrun/utils/regex.py CHANGED
@@ -96,7 +96,14 @@ v3io_stream_consumer_group = [r"^(?!_)[a-zA-Z0-9_]{1,256}$"]
96
96
  # URI patterns
97
97
  run_uri_pattern = r"^(?P<project>.*)@(?P<uid>.*)\#(?P<iteration>.*?)(:(?P<tag>.*))?$"
98
98
 
99
- artifact_uri_pattern = r"^((?P<project>.*)/)?(?P<key>.*?)(\#(?P<iteration>.*?))?(:(?P<tag>.*?))?(@(?P<tree>.*))?$"
99
+ artifact_uri_pattern = (
100
+ r"^((?P<project>.*)/)?" # Optional project
101
+ r"(?P<key>.*?)" # Key
102
+ r"(\#(?P<iteration>.*?))?" # Optional iteration
103
+ r"(:(?P<tag>.*?))?" # Optional tag
104
+ r"(@(?P<tree>.*?))?" # Optional tree
105
+ r"(\^(?P<uid>.*))?$" # Optional uid
106
+ )
100
107
 
101
108
  artifact_producer_uri_pattern = (
102
109
  r"^((?P<project>.*)/)?(?P<uid>.*?)(\-(?P<iteration>.*?))?$"
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "cb94f845e0a3601e06c7e22381391d82bb386160",
3
- "version": "1.8.0-rc5"
2
+ "git_commit": "5be219a3a066786e96ee697c208cd0f59ef63362",
3
+ "version": "1.8.0-rc9"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mlrun
3
- Version: 1.8.0rc5
3
+ Version: 1.8.0rc9
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -52,7 +52,7 @@ Requires-Dist: deprecated~=1.2
52
52
  Requires-Dist: jinja2>=3.1.3,~=3.1
53
53
  Requires-Dist: orjson<4,>=3.9.15
54
54
  Requires-Dist: mlrun-pipelines-kfp-common~=0.2.3
55
- Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.2; python_version < "3.11"
55
+ Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.3; python_version < "3.11"
56
56
  Requires-Dist: docstring_parser~=0.16
57
57
  Requires-Dist: aiosmtplib~=3.0
58
58
  Provides-Extra: s3