mlrun 1.10.0rc18__py3-none-any.whl → 1.11.0rc16__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 (167) hide show
  1. mlrun/__init__.py +24 -3
  2. mlrun/__main__.py +0 -4
  3. mlrun/artifacts/dataset.py +2 -2
  4. mlrun/artifacts/document.py +6 -1
  5. mlrun/artifacts/llm_prompt.py +21 -15
  6. mlrun/artifacts/model.py +3 -3
  7. mlrun/artifacts/plots.py +1 -1
  8. mlrun/{model_monitoring/db/tsdb/tdengine → auth}/__init__.py +2 -3
  9. mlrun/auth/nuclio.py +89 -0
  10. mlrun/auth/providers.py +429 -0
  11. mlrun/auth/utils.py +415 -0
  12. mlrun/common/constants.py +14 -0
  13. mlrun/common/model_monitoring/helpers.py +123 -0
  14. mlrun/common/runtimes/constants.py +28 -0
  15. mlrun/common/schemas/__init__.py +14 -3
  16. mlrun/common/schemas/alert.py +2 -2
  17. mlrun/common/schemas/api_gateway.py +3 -0
  18. mlrun/common/schemas/auth.py +12 -10
  19. mlrun/common/schemas/client_spec.py +4 -0
  20. mlrun/common/schemas/constants.py +25 -0
  21. mlrun/common/schemas/frontend_spec.py +1 -8
  22. mlrun/common/schemas/function.py +34 -0
  23. mlrun/common/schemas/hub.py +33 -20
  24. mlrun/common/schemas/model_monitoring/__init__.py +2 -1
  25. mlrun/common/schemas/model_monitoring/constants.py +12 -15
  26. mlrun/common/schemas/model_monitoring/functions.py +13 -4
  27. mlrun/common/schemas/model_monitoring/model_endpoints.py +11 -0
  28. mlrun/common/schemas/pipeline.py +1 -1
  29. mlrun/common/schemas/secret.py +17 -2
  30. mlrun/common/secrets.py +95 -1
  31. mlrun/common/types.py +10 -10
  32. mlrun/config.py +69 -19
  33. mlrun/data_types/infer.py +2 -2
  34. mlrun/datastore/__init__.py +12 -5
  35. mlrun/datastore/azure_blob.py +162 -47
  36. mlrun/datastore/base.py +274 -10
  37. mlrun/datastore/datastore.py +7 -2
  38. mlrun/datastore/datastore_profile.py +84 -22
  39. mlrun/datastore/model_provider/huggingface_provider.py +225 -41
  40. mlrun/datastore/model_provider/mock_model_provider.py +87 -0
  41. mlrun/datastore/model_provider/model_provider.py +206 -74
  42. mlrun/datastore/model_provider/openai_provider.py +226 -66
  43. mlrun/datastore/s3.py +39 -18
  44. mlrun/datastore/sources.py +1 -1
  45. mlrun/datastore/store_resources.py +4 -4
  46. mlrun/datastore/storeytargets.py +17 -12
  47. mlrun/datastore/targets.py +1 -1
  48. mlrun/datastore/utils.py +25 -6
  49. mlrun/datastore/v3io.py +1 -1
  50. mlrun/db/base.py +63 -32
  51. mlrun/db/httpdb.py +373 -153
  52. mlrun/db/nopdb.py +54 -21
  53. mlrun/errors.py +4 -2
  54. mlrun/execution.py +66 -25
  55. mlrun/feature_store/api.py +1 -1
  56. mlrun/feature_store/common.py +1 -1
  57. mlrun/feature_store/feature_vector_utils.py +1 -1
  58. mlrun/feature_store/steps.py +8 -6
  59. mlrun/frameworks/_common/utils.py +3 -3
  60. mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
  61. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +2 -1
  62. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
  63. mlrun/frameworks/_ml_common/utils.py +2 -1
  64. mlrun/frameworks/auto_mlrun/auto_mlrun.py +4 -3
  65. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +2 -1
  66. mlrun/frameworks/onnx/dataset.py +2 -1
  67. mlrun/frameworks/onnx/mlrun_interface.py +2 -1
  68. mlrun/frameworks/pytorch/callbacks/logging_callback.py +5 -4
  69. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +2 -1
  70. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +2 -1
  71. mlrun/frameworks/pytorch/utils.py +2 -1
  72. mlrun/frameworks/sklearn/metric.py +2 -1
  73. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +5 -4
  74. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +2 -1
  75. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +2 -1
  76. mlrun/hub/__init__.py +52 -0
  77. mlrun/hub/base.py +142 -0
  78. mlrun/hub/module.py +172 -0
  79. mlrun/hub/step.py +113 -0
  80. mlrun/k8s_utils.py +105 -16
  81. mlrun/launcher/base.py +15 -7
  82. mlrun/launcher/local.py +4 -1
  83. mlrun/model.py +14 -4
  84. mlrun/model_monitoring/__init__.py +0 -1
  85. mlrun/model_monitoring/api.py +65 -28
  86. mlrun/model_monitoring/applications/__init__.py +1 -1
  87. mlrun/model_monitoring/applications/base.py +299 -128
  88. mlrun/model_monitoring/applications/context.py +2 -4
  89. mlrun/model_monitoring/controller.py +132 -58
  90. mlrun/model_monitoring/db/_schedules.py +38 -29
  91. mlrun/model_monitoring/db/_stats.py +6 -16
  92. mlrun/model_monitoring/db/tsdb/__init__.py +9 -7
  93. mlrun/model_monitoring/db/tsdb/base.py +29 -9
  94. mlrun/model_monitoring/db/tsdb/preaggregate.py +234 -0
  95. mlrun/model_monitoring/db/tsdb/stream_graph_steps.py +63 -0
  96. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_metrics_queries.py +414 -0
  97. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_predictions_queries.py +376 -0
  98. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_results_queries.py +590 -0
  99. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connection.py +434 -0
  100. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connector.py +541 -0
  101. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_operations.py +808 -0
  102. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_schema.py +502 -0
  103. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream.py +163 -0
  104. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream_graph_steps.py +60 -0
  105. mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_dataframe_processor.py +141 -0
  106. mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_query_builder.py +585 -0
  107. mlrun/model_monitoring/db/tsdb/timescaledb/writer_graph_steps.py +73 -0
  108. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +20 -9
  109. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +235 -51
  110. mlrun/model_monitoring/features_drift_table.py +2 -1
  111. mlrun/model_monitoring/helpers.py +30 -6
  112. mlrun/model_monitoring/stream_processing.py +34 -28
  113. mlrun/model_monitoring/writer.py +224 -4
  114. mlrun/package/__init__.py +2 -1
  115. mlrun/platforms/__init__.py +0 -43
  116. mlrun/platforms/iguazio.py +8 -4
  117. mlrun/projects/operations.py +17 -11
  118. mlrun/projects/pipelines.py +2 -2
  119. mlrun/projects/project.py +187 -123
  120. mlrun/run.py +95 -21
  121. mlrun/runtimes/__init__.py +2 -186
  122. mlrun/runtimes/base.py +103 -25
  123. mlrun/runtimes/constants.py +225 -0
  124. mlrun/runtimes/daskjob.py +5 -2
  125. mlrun/runtimes/databricks_job/databricks_runtime.py +2 -1
  126. mlrun/runtimes/local.py +5 -2
  127. mlrun/runtimes/mounts.py +20 -2
  128. mlrun/runtimes/nuclio/__init__.py +12 -7
  129. mlrun/runtimes/nuclio/api_gateway.py +36 -6
  130. mlrun/runtimes/nuclio/application/application.py +339 -40
  131. mlrun/runtimes/nuclio/function.py +222 -72
  132. mlrun/runtimes/nuclio/serving.py +132 -42
  133. mlrun/runtimes/pod.py +213 -21
  134. mlrun/runtimes/utils.py +49 -9
  135. mlrun/secrets.py +99 -14
  136. mlrun/serving/__init__.py +2 -0
  137. mlrun/serving/remote.py +84 -11
  138. mlrun/serving/routers.py +26 -44
  139. mlrun/serving/server.py +138 -51
  140. mlrun/serving/serving_wrapper.py +6 -2
  141. mlrun/serving/states.py +997 -283
  142. mlrun/serving/steps.py +62 -0
  143. mlrun/serving/system_steps.py +149 -95
  144. mlrun/serving/v2_serving.py +9 -10
  145. mlrun/track/trackers/mlflow_tracker.py +29 -31
  146. mlrun/utils/helpers.py +292 -94
  147. mlrun/utils/http.py +9 -2
  148. mlrun/utils/notifications/notification/base.py +18 -0
  149. mlrun/utils/notifications/notification/git.py +3 -5
  150. mlrun/utils/notifications/notification/mail.py +39 -16
  151. mlrun/utils/notifications/notification/slack.py +2 -4
  152. mlrun/utils/notifications/notification/webhook.py +2 -5
  153. mlrun/utils/notifications/notification_pusher.py +3 -3
  154. mlrun/utils/version/version.json +2 -2
  155. mlrun/utils/version/version.py +3 -4
  156. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/METADATA +63 -74
  157. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/RECORD +161 -143
  158. mlrun/api/schemas/__init__.py +0 -259
  159. mlrun/db/auth_utils.py +0 -152
  160. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +0 -344
  161. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +0 -75
  162. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +0 -281
  163. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +0 -1266
  164. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/WHEEL +0 -0
  165. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/entry_points.txt +0 -0
  166. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/licenses/LICENSE +0 -0
  167. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/top_level.txt +0 -0
mlrun/__init__.py CHANGED
@@ -24,6 +24,7 @@ __all__ = [
24
24
  "v3io_cred",
25
25
  "auto_mount",
26
26
  "VolumeMount",
27
+ "sync_secret_tokens",
27
28
  ]
28
29
 
29
30
  from os import environ, path
@@ -31,11 +32,13 @@ from typing import Optional
31
32
 
32
33
  import dotenv
33
34
 
35
+ from .common.constants import MLRUN_ACTIVE_PROJECT
34
36
  from .config import config as mlconf
35
37
  from .datastore import DataItem, ModelProvider, store_manager
36
38
  from .db import get_run_db
37
39
  from .errors import MLRunInvalidArgumentError, MLRunNotFoundError
38
40
  from .execution import MLClientCtx
41
+ from .hub import get_hub_item, get_hub_module, get_hub_step, import_module
39
42
  from .model import RunObject, RunTemplate, new_task
40
43
  from .package import ArtifactType, DefaultPackager, Packager, handler
41
44
  from .projects import (
@@ -66,7 +69,7 @@ from .run import (
66
69
  wait_for_pipeline_completion,
67
70
  )
68
71
  from .runtimes import mounts, new_model_server
69
- from .secrets import get_secret_or_env
72
+ from .secrets import get_secret_or_env, sync_secret_tokens
70
73
  from .utils.version import Version
71
74
 
72
75
  __version__ = Version().get()["version"]
@@ -167,11 +170,29 @@ def set_environment(
167
170
 
168
171
 
169
172
  def get_current_project(silent: bool = False) -> Optional[MlrunProject]:
170
- if not pipeline_context.project and not silent:
173
+ if pipeline_context.project:
174
+ return pipeline_context.project
175
+
176
+ project_name = environ.get(MLRUN_ACTIVE_PROJECT, None)
177
+ if not project_name:
178
+ if not silent:
179
+ raise MLRunInvalidArgumentError(
180
+ "No current project is initialized. Use new, get or load project functions first."
181
+ )
182
+ return None
183
+
184
+ project = load_project(
185
+ name=project_name,
186
+ url=project_name,
187
+ save=False,
188
+ sync_functions=False,
189
+ )
190
+
191
+ if not project and not silent:
171
192
  raise MLRunInvalidArgumentError(
172
193
  "No current project is initialized. Use new, get or load project functions first."
173
194
  )
174
- return pipeline_context.project
195
+ return project
175
196
 
176
197
 
177
198
  def get_sample_path(subpath=""):
mlrun/__main__.py CHANGED
@@ -203,7 +203,6 @@ def main():
203
203
  @click.option(
204
204
  "--allow-cross-project",
205
205
  is_flag=True,
206
- default=True, # TODO: remove this default in 1.11
207
206
  help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
208
207
  "as a baseline for a new project with a different name",
209
208
  )
@@ -513,7 +512,6 @@ def run(
513
512
  @click.option(
514
513
  "--allow-cross-project",
515
514
  is_flag=True,
516
- default=True, # TODO: remove this default in 1.11
517
515
  help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
518
516
  "as a baseline for a new project with a different name",
519
517
  )
@@ -672,7 +670,6 @@ def build(
672
670
  @click.option(
673
671
  "--allow-cross-project",
674
672
  is_flag=True,
675
- default=True, # TODO: remove this default in 1.11
676
673
  help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
677
674
  "as a baseline for a new project with a different name",
678
675
  )
@@ -1008,7 +1005,6 @@ def logs(uid, project, offset, db):
1008
1005
  @click.option(
1009
1006
  "--allow-cross-project",
1010
1007
  is_flag=True,
1011
- default=True, # TODO: remove this default in 1.11
1012
1008
  help="Override the loaded project name. This flag ensures awareness of loading an existing project yaml "
1013
1009
  "as a baseline for a new project with a different name",
1014
1010
  )
@@ -366,9 +366,9 @@ def get_df_stats(df):
366
366
  for col, values in df.describe(include="all").items():
367
367
  stats_dict = {}
368
368
  for stat, val in values.dropna().items():
369
- if isinstance(val, (float, np.floating, np.float64)):
369
+ if isinstance(val, float | np.floating | np.float64):
370
370
  stats_dict[stat] = float(val)
371
- elif isinstance(val, (int, np.integer, np.int64)):
371
+ elif isinstance(val, int | np.integer | np.int64):
372
372
  stats_dict[stat] = int(val)
373
373
  else:
374
374
  stats_dict[stat] = str(val)
@@ -359,7 +359,12 @@ class DocumentArtifact(Artifact):
359
359
  self,
360
360
  splitter: Optional["TextSplitter"] = None, # noqa: F821
361
361
  ) -> list["Document"]: # noqa: F821
362
- from langchain.schema import Document
362
+ # Try new langchain 1.0+ import path first
363
+ try:
364
+ from langchain_core.documents import Document
365
+ except ImportError:
366
+ # Fall back to old langchain <1.0 import path
367
+ from langchain.schema import Document
363
368
 
364
369
  """
365
370
  Create LC documents from the artifact
@@ -29,7 +29,7 @@ class LLMPromptArtifactSpec(ArtifactSpec):
29
29
  _dict_fields = ArtifactSpec._dict_fields + [
30
30
  "prompt_template",
31
31
  "prompt_legend",
32
- "model_configuration",
32
+ "invocation_config",
33
33
  "description",
34
34
  ]
35
35
  PROMPT_TEMPLATE_KEYS = ("content", "role")
@@ -41,7 +41,7 @@ class LLMPromptArtifactSpec(ArtifactSpec):
41
41
  prompt_template: Optional[list[dict]] = None,
42
42
  prompt_path: Optional[str] = None,
43
43
  prompt_legend: Optional[dict] = None,
44
- model_configuration: Optional[dict] = None,
44
+ invocation_config: Optional[dict] = None,
45
45
  description: Optional[str] = None,
46
46
  target_path: Optional[str] = None,
47
47
  **kwargs,
@@ -62,12 +62,17 @@ class LLMPromptArtifactSpec(ArtifactSpec):
62
62
  parent_uri=model_artifact.uri
63
63
  if isinstance(model_artifact, model_art.ModelArtifact)
64
64
  else model_artifact,
65
+ format=kwargs.pop("format", "") or "json",
65
66
  **kwargs,
66
67
  )
67
68
 
68
69
  self.prompt_template = prompt_template
69
70
  self.prompt_legend = prompt_legend
70
- self.model_configuration = model_configuration
71
+ if invocation_config is not None and not isinstance(invocation_config, dict):
72
+ raise mlrun.errors.MLRunInvalidArgumentError(
73
+ "LLMPromptArtifact invocation_config must be a dictionary or None"
74
+ )
75
+ self.invocation_config = invocation_config or {}
71
76
  self.description = description
72
77
  self._model_artifact = (
73
78
  model_artifact
@@ -83,19 +88,20 @@ class LLMPromptArtifactSpec(ArtifactSpec):
83
88
  raise mlrun.errors.MLRunInvalidArgumentError(
84
89
  "Expected prompt_template to be a list of dicts"
85
90
  )
86
- keys_to_pop = []
87
91
  for message in prompt_template:
92
+ if set(key.lower() for key in message.keys()) != set(
93
+ self.PROMPT_TEMPLATE_KEYS
94
+ ):
95
+ raise mlrun.errors.MLRunInvalidArgumentError(
96
+ f"Expected prompt_template to contain dicts with keys "
97
+ f"{self.PROMPT_TEMPLATE_KEYS}, got {message.keys()}"
98
+ )
99
+ keys_to_pop = []
88
100
  for key in message.keys():
89
101
  if isinstance(key, str):
90
- if key.lower() not in self.PROMPT_TEMPLATE_KEYS:
91
- raise mlrun.errors.MLRunInvalidArgumentError(
92
- f"Expected prompt_template to contain dict that "
93
- f"only has keys from {self.PROMPT_TEMPLATE_KEYS}"
94
- )
95
- else:
96
- if not key.islower():
97
- message[key.lower()] = message[key]
98
- keys_to_pop.append(key)
102
+ if not key.islower():
103
+ message[key.lower()] = message[key]
104
+ keys_to_pop.append(key)
99
105
  else:
100
106
  raise mlrun.errors.MLRunInvalidArgumentError(
101
107
  f"Expected prompt_template to contain dict that only"
@@ -169,7 +175,7 @@ class LLMPromptArtifact(Artifact):
169
175
  prompt_template: Optional[list[dict]] = None,
170
176
  prompt_path: Optional[str] = None,
171
177
  prompt_legend: Optional[dict] = None,
172
- model_configuration: Optional[dict] = None,
178
+ invocation_config: Optional[dict] = None,
173
179
  description: Optional[str] = None,
174
180
  target_path=None,
175
181
  **kwargs,
@@ -179,7 +185,7 @@ class LLMPromptArtifact(Artifact):
179
185
  prompt_path=prompt_path,
180
186
  prompt_legend=prompt_legend,
181
187
  model_artifact=model_artifact,
182
- model_configuration=model_configuration,
188
+ invocation_config=invocation_config,
183
189
  target_path=target_path,
184
190
  description=description,
185
191
  )
mlrun/artifacts/model.py CHANGED
@@ -190,10 +190,10 @@ class ModelArtifact(Artifact):
190
190
  """
191
191
  super().__init__(key, body, format=format, target_path=target_path, **kwargs)
192
192
  model_file = str(model_file or "")
193
- if model_file and model_url:
193
+ if (model_file or model_dir or body) and model_url:
194
194
  raise mlrun.errors.MLRunInvalidArgumentError(
195
- "Arguments 'model_file' and 'model_dir' cannot be"
196
- " used together with 'model_url'."
195
+ "Arguments 'model_file' and 'model_url' cannot be"
196
+ " used together with 'model_file', 'model_dir' or 'body'."
197
197
  )
198
198
  if model_file and "/" in model_file:
199
199
  if model_dir:
mlrun/artifacts/plots.py CHANGED
@@ -42,7 +42,7 @@ class PlotArtifact(Artifact):
42
42
  import matplotlib
43
43
 
44
44
  if not self.spec.get_body() or not isinstance(
45
- self.spec.get_body(), (bytes, matplotlib.figure.Figure)
45
+ self.spec.get_body(), bytes | matplotlib.figure.Figure
46
46
  ):
47
47
  raise ValueError(
48
48
  "matplotlib fig or png bytes must be provided as artifact body"
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Iguazio
1
+ # Copyright 2025 Iguazio
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -11,5 +11,4 @@
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
- from .tdengine_connector import TDEngineConnector
14
+ from .providers import IGTokenProvider, OAuthClientIDTokenProvider, StaticTokenProvider
mlrun/auth/nuclio.py ADDED
@@ -0,0 +1,89 @@
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 base64
16
+
17
+ import requests.auth
18
+ from nuclio.auth import AuthInfo as _NuclioAuthInfo
19
+ from nuclio.auth import AuthKinds as NuclioAuthKinds
20
+
21
+ import mlrun.auth.providers
22
+ import mlrun.common.schemas.auth
23
+
24
+
25
+ class NuclioAuthInfo(_NuclioAuthInfo):
26
+ def __init__(self, token=None, **kwargs):
27
+ super().__init__(**kwargs)
28
+ self._token = token
29
+
30
+ @classmethod
31
+ def from_auth_info(cls, auth_info: "mlrun.common.schemas.auth.AuthInfo"):
32
+ if not auth_info:
33
+ return None
34
+ if mlrun.mlconf.is_iguazio_v4_mode():
35
+ return cls.from_request_headers(auth_info.request_headers)
36
+ if auth_info.session != "":
37
+ return NuclioAuthInfo(
38
+ password=auth_info.session, mode=NuclioAuthKinds.iguazio
39
+ )
40
+ return None
41
+
42
+ @classmethod
43
+ def from_request_headers(cls, headers: dict[str, str]):
44
+ if not headers:
45
+ return cls()
46
+ for key, value in headers.items():
47
+ if key.lower() == "authorization":
48
+ if value.lower().startswith("bearer "):
49
+ return cls(
50
+ token=value[len("bearer ") :],
51
+ mode=NuclioAuthKinds.iguazio,
52
+ )
53
+ if value.lower().startswith("basic "):
54
+ token = value[len("basic ") :]
55
+ decoded_token = base64.b64decode(token).decode("utf-8")
56
+ username, password = decoded_token.split(":", 1)
57
+ return cls(
58
+ username=username,
59
+ password=password,
60
+ mode=NuclioAuthKinds.iguazio,
61
+ )
62
+ return cls()
63
+
64
+ @classmethod
65
+ def from_envvar(cls):
66
+ if mlrun.mlconf.is_iguazio_v4_mode():
67
+ token_provider = mlrun.auth.providers.IGTokenProvider(
68
+ token_endpoint=mlrun.mlconf.auth_token_endpoint,
69
+ )
70
+ return cls(
71
+ token=token_provider.get_token(),
72
+ mode=NuclioAuthKinds.iguazio,
73
+ )
74
+ return super().from_envvar()
75
+
76
+ def to_requests_auth(self) -> "requests.auth":
77
+ if self._token:
78
+ # in iguazio v4 mode we use bearer token auth
79
+ return _RequestAuthBearerToken(self._token)
80
+ return super().to_requests_auth()
81
+
82
+
83
+ class _RequestAuthBearerToken(requests.auth.AuthBase):
84
+ def __init__(self, token: str):
85
+ self._token = token
86
+
87
+ def __call__(self, r):
88
+ r.headers["Authorization"] = f"Bearer {self._token}"
89
+ return r