mlrun 1.7.0rc4__py3-none-any.whl → 1.7.0rc5__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.

mlrun/common/constants.py CHANGED
@@ -13,4 +13,5 @@
13
13
  # limitations under the License.
14
14
  #
15
15
  IMAGE_NAME_ENRICH_REGISTRY_PREFIX = "." # prefix for image name to enrich with registry
16
+ MLRUN_CREATED_LABEL = "mlrun-created"
16
17
  MYSQL_MEDIUMBLOB_SIZE_BYTES = 16 * 1024 * 1024
@@ -14,6 +14,16 @@
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 .api_gateway import (
18
+ APIGateway,
19
+ APIGatewayAuthenticationMode,
20
+ APIGatewayBasicAuth,
21
+ APIGatewayMetadata,
22
+ APIGatewaysOutput,
23
+ APIGatewaySpec,
24
+ APIGatewayStatus,
25
+ APIGatewayUpstream,
26
+ )
17
27
  from .artifact import (
18
28
  Artifact,
19
29
  ArtifactCategories,
@@ -0,0 +1,85 @@
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 typing
16
+ from typing import Optional
17
+
18
+ import pydantic
19
+
20
+ import mlrun.common.types
21
+
22
+
23
+ class APIGatewayAuthenticationMode(mlrun.common.types.StrEnum):
24
+ basic = "basicAuth"
25
+ none = "none"
26
+
27
+ @classmethod
28
+ def from_str(cls, authentication_mode: str):
29
+ if authentication_mode == "none":
30
+ return cls.none
31
+ elif authentication_mode == "basicAuth":
32
+ return cls.basic
33
+ else:
34
+ raise mlrun.errors.MLRunInvalidArgumentError(
35
+ f"Authentication mode `{authentication_mode}` is not supported",
36
+ )
37
+
38
+
39
+ class _APIGatewayBaseModel(pydantic.BaseModel):
40
+ class Config:
41
+ extra = pydantic.Extra.allow
42
+
43
+
44
+ class APIGatewayMetadata(_APIGatewayBaseModel):
45
+ name: str
46
+ namespace: Optional[str]
47
+ labels: Optional[dict] = {}
48
+
49
+
50
+ class APIGatewayBasicAuth(_APIGatewayBaseModel):
51
+ username: str
52
+ password: str
53
+
54
+
55
+ class APIGatewayUpstream(_APIGatewayBaseModel):
56
+ kind: Optional[str] = "nucliofunction"
57
+ nucliofunction: dict[str, str]
58
+ percentage: Optional[int] = 0
59
+
60
+
61
+ class APIGatewaySpec(_APIGatewayBaseModel):
62
+ name: str
63
+ description: Optional[str]
64
+ path: Optional[str] = "/"
65
+ authenticationMode: Optional[APIGatewayAuthenticationMode] = (
66
+ APIGatewayAuthenticationMode.none
67
+ )
68
+ upstreams: list[APIGatewayUpstream]
69
+ authentication: Optional[dict[str, Optional[APIGatewayBasicAuth]]]
70
+ host: Optional[str]
71
+
72
+
73
+ class APIGatewayStatus(_APIGatewayBaseModel):
74
+ name: Optional[str]
75
+ state: Optional[str]
76
+
77
+
78
+ class APIGateway(_APIGatewayBaseModel):
79
+ metadata: APIGatewayMetadata
80
+ spec: APIGatewaySpec
81
+ status: Optional[APIGatewayStatus]
82
+
83
+
84
+ class APIGatewaysOutput(_APIGatewayBaseModel):
85
+ api_gateways: typing.Optional[dict[str, APIGateway]] = {}
@@ -59,7 +59,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
59
59
  hub_source = "hub-source"
60
60
  workflow = "workflow"
61
61
  datastore_profile = "datastore-profile"
62
- api_gateways = "api-gateways"
62
+ api_gateway = "api-gateway"
63
63
 
64
64
  def to_resource_string(
65
65
  self,
@@ -94,7 +94,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
94
94
  AuthorizationResourceTypes.hub_source: "/marketplace/sources",
95
95
  # workflow define how to run a pipeline and can be considered as the specification of a pipeline.
96
96
  AuthorizationResourceTypes.workflow: "/projects/{project_name}/workflows/{resource_name}",
97
- AuthorizationResourceTypes.api_gateways: "/projects/{project_name}/api-gateways",
97
+ AuthorizationResourceTypes.api_gateway: "/projects/{project_name}/api-gateways/{resource_name}",
98
98
  }[self].format(project_name=project_name, resource_name=resource_name)
99
99
 
100
100
 
mlrun/config.py CHANGED
@@ -1348,12 +1348,21 @@ def read_env(env=None, prefix=env_prefix):
1348
1348
  if igz_domain:
1349
1349
  config["ui_url"] = f"https://mlrun-ui.{igz_domain}"
1350
1350
 
1351
- if config.get("log_level"):
1351
+ if log_level := config.get("log_level"):
1352
1352
  import mlrun.utils.logger
1353
1353
 
1354
1354
  # logger created (because of imports mess) before the config is loaded (in tests), therefore we're changing its
1355
1355
  # level manually
1356
- mlrun.utils.logger.set_logger_level(config["log_level"])
1356
+ mlrun.utils.logger.set_logger_level(log_level)
1357
+
1358
+ if log_formatter_name := config.get("log_formatter"):
1359
+ import mlrun.utils.logger
1360
+
1361
+ log_formatter = mlrun.utils.create_formatter_instance(
1362
+ mlrun.utils.FormatterKinds(log_formatter_name)
1363
+ )
1364
+ mlrun.utils.logger.get_handler("default").setFormatter(log_formatter)
1365
+
1357
1366
  # The default function pod resource values are of type str; however, when reading from environment variable numbers,
1358
1367
  # it converts them to type int if contains only number, so we want to convert them to str.
1359
1368
  _convert_resources_to_str(config)
@@ -451,7 +451,7 @@ class BaseStoreTarget(DataTargetBase):
451
451
  self.get_target_path(),
452
452
  credentials_prefix_secrets,
453
453
  )
454
- return store, url
454
+ return store, resolved_store_path, url
455
455
 
456
456
  def _get_column_list(self, features, timestamp_key, key_columns, with_type=False):
457
457
  result = []
@@ -500,7 +500,7 @@ class BaseStoreTarget(DataTargetBase):
500
500
  write_spark_dataframe_with_options(options, df, "overwrite")
501
501
  elif hasattr(df, "dask"):
502
502
  dask_options = self.get_dask_options()
503
- store, target_path = self._get_store_and_path()
503
+ store, path_in_store, target_path = self._get_store_and_path()
504
504
  storage_options = store.get_storage_options()
505
505
  df = df.repartition(partition_size="100MB")
506
506
  try:
@@ -521,7 +521,7 @@ class BaseStoreTarget(DataTargetBase):
521
521
  except Exception as exc:
522
522
  raise RuntimeError("Failed to write Dask Dataframe") from exc
523
523
  else:
524
- store, target_path = self._get_store_and_path()
524
+ store, path_in_store, target_path = self._get_store_and_path()
525
525
  target_path = generate_path_with_chunk(self, chunk_id, target_path)
526
526
  file_system = store.filesystem
527
527
  if file_system.protocol == "file":
@@ -688,7 +688,7 @@ class BaseStoreTarget(DataTargetBase):
688
688
  raise NotImplementedError()
689
689
 
690
690
  def purge(self):
691
- store, target_path = self._get_store_and_path()
691
+ store, path_in_store, target_path = self._get_store_and_path()
692
692
  store.rm(target_path, recursive=True)
693
693
 
694
694
  def as_df(
@@ -868,7 +868,7 @@ class ParquetTarget(BaseStoreTarget):
868
868
  for key_column in key_columns:
869
869
  tuple_key_columns.append((key_column.name, key_column.value_type))
870
870
 
871
- store, target_path = self._get_store_and_path()
871
+ store, path_in_store, target_path = self._get_store_and_path()
872
872
 
873
873
  storage_options = store.get_storage_options()
874
874
  if storage_options and self.storage_options:
@@ -921,9 +921,7 @@ class ParquetTarget(BaseStoreTarget):
921
921
  if unit == time_partitioning_granularity:
922
922
  break
923
923
 
924
- store, path, url = mlrun.store_manager.get_or_create_store(
925
- self.get_target_path()
926
- )
924
+ store, path, url = self._get_store_and_path()
927
925
  spark_options = store.get_spark_options()
928
926
  spark_options.update(
929
927
  {
@@ -1042,7 +1040,7 @@ class CSVTarget(BaseStoreTarget):
1042
1040
  column_list = self._get_column_list(
1043
1041
  features=features, timestamp_key=timestamp_key, key_columns=key_columns
1044
1042
  )
1045
- store, target_path = self._get_store_and_path()
1043
+ store, path_in_store, target_path = self._get_store_and_path()
1046
1044
  graph.add_step(
1047
1045
  name=self.name or "CSVTarget",
1048
1046
  after=after,
@@ -1057,9 +1055,7 @@ class CSVTarget(BaseStoreTarget):
1057
1055
  )
1058
1056
 
1059
1057
  def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
1060
- store, path, url = mlrun.store_manager.get_or_create_store(
1061
- self.get_target_path()
1062
- )
1058
+ store, path, url = self._get_store_and_path()
1063
1059
  spark_options = store.get_spark_options()
1064
1060
  spark_options.update(
1065
1061
  {
@@ -1193,7 +1189,7 @@ class NoSqlBaseTarget(BaseStoreTarget):
1193
1189
  df = df.copy(deep=False)
1194
1190
  access_key = self._get_credential("V3IO_ACCESS_KEY")
1195
1191
 
1196
- store, target_path = self._get_store_and_path()
1192
+ store, path_in_store, target_path = self._get_store_and_path()
1197
1193
  storage_options = store.get_storage_options()
1198
1194
  access_key = storage_options.get("v3io_access_key", access_key)
1199
1195
 
@@ -1215,7 +1211,7 @@ class NoSqlTarget(NoSqlBaseTarget):
1215
1211
  def get_table_object(self):
1216
1212
  from storey import Table, V3ioDriver
1217
1213
 
1218
- store, target_path = self._get_store_and_path()
1214
+ store, path_in_store, target_path = self._get_store_and_path()
1219
1215
  endpoint, uri = parse_path(target_path)
1220
1216
  storage_options = store.get_storage_options()
1221
1217
  access_key = storage_options.get("v3io_access_key")
@@ -1227,7 +1223,7 @@ class NoSqlTarget(NoSqlBaseTarget):
1227
1223
  )
1228
1224
 
1229
1225
  def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
1230
- store, target_path = self._get_store_and_path()
1226
+ store, path_in_store, target_path = self._get_store_and_path()
1231
1227
  storage_options = store.get_storage_options()
1232
1228
  store_access_key = storage_options.get("v3io_access_key")
1233
1229
  env_access_key = self._secrets.get(
@@ -1239,7 +1235,7 @@ class NoSqlTarget(NoSqlBaseTarget):
1239
1235
  "Spark will disregard the store-provided key."
1240
1236
  )
1241
1237
  spark_options = {
1242
- "path": store.spark_url + target_path,
1238
+ "path": store.spark_url + path_in_store,
1243
1239
  "format": "io.iguaz.v3io.spark.sql.kv",
1244
1240
  }
1245
1241
  if isinstance(key_column, list) and len(key_column) >= 1:
@@ -1332,10 +1328,10 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
1332
1328
  def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
1333
1329
  endpoint, uri = self._get_server_endpoint()
1334
1330
  parsed_endpoint = urlparse(endpoint)
1335
- store, path = self._get_store_and_path()
1331
+ store, path_in_store, path = self._get_store_and_path()
1336
1332
  return {
1337
1333
  "key.column": "_spark_object_name",
1338
- "table": "{" + store.spark_url + path,
1334
+ "table": "{" + path_in_store,
1339
1335
  "format": "org.apache.spark.sql.redis",
1340
1336
  "host": parsed_endpoint.hostname,
1341
1337
  "port": parsed_endpoint.port,
@@ -1383,7 +1379,7 @@ class StreamTarget(BaseStoreTarget):
1383
1379
  from storey import V3ioDriver
1384
1380
 
1385
1381
  key_columns = list(key_columns.keys())
1386
- store, path = self._get_store_and_path()
1382
+ store, path_in_store, path = self._get_store_and_path()
1387
1383
  if not path:
1388
1384
  raise mlrun.errors.MLRunInvalidArgumentError("StreamTarget requires a path")
1389
1385
  endpoint, uri = parse_path(path)
@@ -1537,7 +1533,7 @@ class TSDBTarget(BaseStoreTarget):
1537
1533
  key_column = [key_column]
1538
1534
  new_index.extend(key_column)
1539
1535
 
1540
- store, target_path = self._get_store_and_path()
1536
+ store, path_in_store, target_path = self._get_store_and_path()
1541
1537
  storage_options = store.get_storage_options()
1542
1538
  access_key = storage_options.get("v3io_access_key", access_key)
1543
1539
 
mlrun/db/base.py CHANGED
@@ -616,6 +616,22 @@ class RunDBInterface(ABC):
616
616
  ):
617
617
  pass
618
618
 
619
+ @abstractmethod
620
+ def store_api_gateway(
621
+ self,
622
+ project: str,
623
+ api_gateway: mlrun.common.schemas.APIGateway,
624
+ ):
625
+ pass
626
+
627
+ @abstractmethod
628
+ def list_api_gateways(self, project=None) -> mlrun.common.schemas.APIGatewaysOutput:
629
+ pass
630
+
631
+ @abstractmethod
632
+ def get_api_gateway(self, name, project=None) -> mlrun.common.schemas.APIGateway:
633
+ pass
634
+
619
635
  def get_builder_status(
620
636
  self,
621
637
  func: "mlrun.runtimes.BaseRuntime",
mlrun/db/httpdb.py CHANGED
@@ -33,6 +33,7 @@ import mlrun.common.schemas
33
33
  import mlrun.model_monitoring.model_endpoint
34
34
  import mlrun.platforms
35
35
  import mlrun.projects
36
+ import mlrun.runtimes.nuclio.api_gateway
36
37
  from mlrun.errors import MLRunInvalidArgumentError, err_to_str
37
38
 
38
39
  from ..artifacts import Artifact
@@ -3369,20 +3370,61 @@ class HTTPRunDB(RunDBInterface):
3369
3370
  body=dict_to_json(authorization_verification_input.dict()),
3370
3371
  )
3371
3372
 
3372
- def list_api_gateways(self, project=None):
3373
+ def list_api_gateways(self, project=None) -> mlrun.common.schemas.APIGatewaysOutput:
3373
3374
  """
3374
3375
  Returns a list of Nuclio api gateways
3375
- :param project: optional str parameter to filter by project, if not passed, default Nuclio's value is taken
3376
+ :param project: optional str parameter to filter by project, if not passed, default project value is taken
3376
3377
 
3377
- :return: json with the list of Nuclio Api Gateways
3378
- (json example is here
3379
- https://github.com/nuclio/nuclio/blob/development/docs/reference/api/README.md#listing-all-api-gateways)
3378
+ :return: :py:class:`~mlrun.common.schemas.APIGateways`.
3380
3379
  """
3381
3380
  project = project or config.default_project
3382
3381
  error = "list api gateways"
3383
- endpoint_path = f"projects/{project}/nuclio/api-gateways"
3384
- resp = self.api_call("GET", endpoint_path, error)
3385
- return resp.json()
3382
+ endpoint_path = f"projects/{project}/api-gateways"
3383
+ response = self.api_call("GET", endpoint_path, error)
3384
+ return mlrun.common.schemas.APIGatewaysOutput(**response.json())
3385
+
3386
+ def get_api_gateway(self, name, project=None) -> mlrun.common.schemas.APIGateway:
3387
+ """
3388
+ Returns an API gateway
3389
+ :param name: API gateway name
3390
+ :param project: optional str parameter to filter by project, if not passed, default project value is taken
3391
+
3392
+ :return: :py:class:`~mlrun.common.schemas.APIGateway`.
3393
+ """
3394
+ project = project or config.default_project
3395
+ error = "get api gateway"
3396
+ endpoint_path = f"projects/{project}/api-gateways/{name}"
3397
+ response = self.api_call("GET", endpoint_path, error)
3398
+ return mlrun.common.schemas.APIGateway(**response.json())
3399
+
3400
+ def store_api_gateway(
3401
+ self,
3402
+ api_gateway: Union[
3403
+ mlrun.common.schemas.APIGateway,
3404
+ mlrun.runtimes.nuclio.api_gateway.APIGateway,
3405
+ ],
3406
+ project: Optional[str] = None,
3407
+ ) -> mlrun.common.schemas.APIGateway:
3408
+ """
3409
+ Stores an API Gateway.
3410
+ :param api_gateway :py:class:`~mlrun.runtimes.nuclio.APIGateway`
3411
+ or :py:class:`~mlrun.common.schemas.APIGateway`: API Gateway entity.
3412
+ :param project: project name. Mandatory if api_gateway is mlrun.common.schemas.APIGateway.
3413
+
3414
+ :return: :py:class:`~mlrun.common.schemas.APIGateway`.
3415
+ """
3416
+
3417
+ if isinstance(api_gateway, mlrun.runtimes.nuclio.api_gateway.APIGateway):
3418
+ api_gateway = api_gateway.to_scheme()
3419
+ endpoint_path = f"projects/{project}/api-gateways/{api_gateway.metadata.name}"
3420
+ error = "store api gateways"
3421
+ response = self.api_call(
3422
+ "PUT",
3423
+ endpoint_path,
3424
+ error,
3425
+ json=api_gateway.dict(exclude_unset=True, exclude_none=True),
3426
+ )
3427
+ return mlrun.common.schemas.APIGateway(**response.json())
3386
3428
 
3387
3429
  def trigger_migrations(self) -> Optional[mlrun.common.schemas.BackgroundTask]:
3388
3430
  """Trigger migrations (will do nothing if no migrations are needed) and wait for them to finish if actually
mlrun/db/nopdb.py CHANGED
@@ -506,6 +506,19 @@ class NopDB(RunDBInterface):
506
506
  ):
507
507
  pass
508
508
 
509
+ def store_api_gateway(
510
+ self,
511
+ project: str,
512
+ api_gateway: mlrun.runtimes.nuclio.APIGateway,
513
+ ) -> mlrun.common.schemas.APIGateway:
514
+ pass
515
+
516
+ def list_api_gateways(self, project=None):
517
+ pass
518
+
519
+ def get_api_gateway(self, name, project=None):
520
+ pass
521
+
509
522
  def verify_authorization(
510
523
  self,
511
524
  authorization_verification_input: mlrun.common.schemas.AuthorizationVerificationInput,
mlrun/projects/project.py CHANGED
@@ -41,6 +41,7 @@ import mlrun.db
41
41
  import mlrun.errors
42
42
  import mlrun.k8s_utils
43
43
  import mlrun.runtimes
44
+ import mlrun.runtimes.nuclio.api_gateway
44
45
  import mlrun.runtimes.pod
45
46
  import mlrun.runtimes.utils
46
47
  import mlrun.utils.regex
@@ -3625,6 +3626,64 @@ class MlrunProject(ModelObj):
3625
3626
  """
3626
3627
  self.spec.remove_custom_packager(packager=packager)
3627
3628
 
3629
+ def store_api_gateway(
3630
+ self, api_gateway: mlrun.runtimes.nuclio.api_gateway.APIGateway
3631
+ ) -> mlrun.runtimes.nuclio.api_gateway.APIGateway:
3632
+ """
3633
+ Creates or updates a Nuclio API Gateway using the provided APIGateway object.
3634
+
3635
+ This method interacts with the MLRun service to create/update a Nuclio API Gateway based on the provided
3636
+ APIGateway object. Once done, it returns the updated APIGateway object containing all fields propagated
3637
+ on MLRun and Nuclio sides, such as the 'host' attribute.
3638
+ Nuclio docs here: https://docs.nuclio.io/en/latest/reference/api-gateway/http.html
3639
+
3640
+ :param api_gateway: An instance of :py:class:`~mlrun.runtimes.nuclio.APIGateway` representing the configuration
3641
+ of the API Gateway to be created
3642
+
3643
+ @return: An instance of :py:class:`~mlrun.runtimes.nuclio.APIGateway` with all fields populated based on the
3644
+ information retrieved from the Nuclio API
3645
+ """
3646
+
3647
+ api_gateway_json = mlrun.db.get_run_db().store_api_gateway(
3648
+ api_gateway=api_gateway,
3649
+ project=self.name,
3650
+ )
3651
+
3652
+ if api_gateway_json:
3653
+ # fill in all the fields in the user's api_gateway object
3654
+ api_gateway = mlrun.runtimes.nuclio.api_gateway.APIGateway.from_scheme(
3655
+ api_gateway_json
3656
+ )
3657
+ return api_gateway
3658
+
3659
+ def list_api_gateways(self) -> list[mlrun.runtimes.nuclio.api_gateway.APIGateway]:
3660
+ """
3661
+ Retrieves a list of Nuclio API gateways associated with the project.
3662
+
3663
+ @return: List of :py:class:`~mlrun.runtimes.nuclio.api_gateway.APIGateway` objects representing
3664
+ the Nuclio API gateways associated with the project.
3665
+ """
3666
+ gateways_list = mlrun.db.get_run_db().list_api_gateways(self.name)
3667
+ return [
3668
+ mlrun.runtimes.nuclio.api_gateway.APIGateway.from_scheme(gateway_dict)
3669
+ for gateway_dict in gateways_list.api_gateways.values()
3670
+ ]
3671
+
3672
+ def get_api_gateway(
3673
+ self,
3674
+ name: str,
3675
+ ) -> mlrun.runtimes.nuclio.api_gateway.APIGateway:
3676
+ """
3677
+ Retrieves an API gateway by name instance.
3678
+
3679
+ :param name: The name of the API gateway to retrieve.
3680
+
3681
+ Returns:
3682
+ mlrun.runtimes.nuclio.APIGateway: An instance of APIGateway.
3683
+ """
3684
+
3685
+ return mlrun.db.get_run_db().get_api_gateway(name=name, project=self.name)
3686
+
3628
3687
  def _run_authenticated_git_action(
3629
3688
  self,
3630
3689
  action: Callable,
mlrun/run.py CHANGED
@@ -628,7 +628,7 @@ def code_to_function(
628
628
  - spark: run distributed Spark job using Spark Kubernetes Operator
629
629
  - remote-spark: run distributed Spark job on remote Spark service
630
630
 
631
- Learn more about {Kinds of function (runtimes)](../concepts/functions-overview.html).
631
+ Learn more about [Kinds of function (runtimes)](../concepts/functions-overview.html).
632
632
 
633
633
  :param name: function name, typically best to use hyphen-case
634
634
  :param project: project used to namespace the function, defaults to 'default'
mlrun/runtimes/base.py CHANGED
@@ -138,20 +138,24 @@ class FunctionSpec(ModelObj):
138
138
 
139
139
  @property
140
140
  def clone_target_dir(self):
141
- warnings.warn(
142
- "The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.8.0. "
143
- "Use spec.build.source_code_target_dir instead.",
144
- FutureWarning,
145
- )
141
+ # TODO: remove this property in 1.9.0
142
+ if self.build.source_code_target_dir:
143
+ warnings.warn(
144
+ "The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.9.0. "
145
+ "Use spec.build.source_code_target_dir instead.",
146
+ FutureWarning,
147
+ )
146
148
  return self.build.source_code_target_dir
147
149
 
148
150
  @clone_target_dir.setter
149
151
  def clone_target_dir(self, clone_target_dir):
150
- warnings.warn(
151
- "The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.8.0. "
152
- "Use spec.build.source_code_target_dir instead.",
153
- FutureWarning,
154
- )
152
+ # TODO: remove this property in 1.9.0
153
+ if clone_target_dir:
154
+ warnings.warn(
155
+ "The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.9.0. "
156
+ "Use spec.build.source_code_target_dir instead.",
157
+ FutureWarning,
158
+ )
155
159
  self.build.source_code_target_dir = clone_target_dir
156
160
 
157
161
  def enrich_function_preemption_spec(self):
@@ -18,3 +18,4 @@ from .function import (
18
18
  min_nuclio_versions,
19
19
  RemoteRuntime,
20
20
  ) # noqa
21
+ from .api_gateway import APIGateway
@@ -0,0 +1,300 @@
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
+ import base64
15
+ from typing import Optional, Union
16
+ from urllib.parse import urljoin
17
+
18
+ import requests
19
+
20
+ import mlrun
21
+ import mlrun.common.schemas
22
+
23
+ from .function import RemoteRuntime
24
+ from .serving import ServingRuntime
25
+
26
+ NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH = "basicAuth"
27
+ NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE = "none"
28
+ PROJECT_NAME_LABEL = "nuclio.io/project-name"
29
+
30
+
31
+ class APIGateway:
32
+ def __init__(
33
+ self,
34
+ project,
35
+ name: str,
36
+ functions: Union[
37
+ list[str],
38
+ Union[
39
+ list[
40
+ Union[
41
+ RemoteRuntime,
42
+ ServingRuntime,
43
+ ]
44
+ ],
45
+ Union[RemoteRuntime, ServingRuntime],
46
+ ],
47
+ ],
48
+ description: str = "",
49
+ path: str = "/",
50
+ authentication_mode: Optional[
51
+ str
52
+ ] = NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE,
53
+ host: Optional[str] = None,
54
+ canary: Optional[list[int]] = None,
55
+ username: Optional[str] = None,
56
+ password: Optional[str] = None,
57
+ ):
58
+ self.functions = None
59
+ self._validate(
60
+ project=project,
61
+ functions=functions,
62
+ name=name,
63
+ canary=canary,
64
+ username=username,
65
+ password=password,
66
+ )
67
+ self.project = project
68
+ self.name = name
69
+ self.host = host
70
+
71
+ self.path = path
72
+ self.description = description
73
+ self.authentication_mode = (
74
+ authentication_mode
75
+ if authentication_mode
76
+ else self._enrich_authentication_mode(username=username, password=password)
77
+ )
78
+ self.canary = canary
79
+ self._username = username
80
+ self._password = password
81
+
82
+ def invoke(
83
+ self,
84
+ method="POST",
85
+ headers: dict = {},
86
+ auth: Optional[tuple[str, str]] = None,
87
+ **kwargs,
88
+ ):
89
+ if not self.invoke_url:
90
+ raise mlrun.errors.MLRunInvalidArgumentError(
91
+ "Invocation url is not set. Set up gateway's `invoke_url` attribute."
92
+ )
93
+ if (
94
+ self.authentication_mode
95
+ == NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
96
+ and not auth
97
+ ):
98
+ raise mlrun.errors.MLRunInvalidArgumentError(
99
+ "API Gateway invocation requires authentication. Please pass credentials"
100
+ )
101
+ if auth:
102
+ headers["Authorization"] = self._generate_basic_auth(*auth)
103
+ return requests.request(
104
+ method=method, url=self.invoke_url, headers=headers, **kwargs
105
+ )
106
+
107
+ @classmethod
108
+ def from_scheme(cls, api_gateway: mlrun.common.schemas.APIGateway):
109
+ project = api_gateway.metadata.labels.get(PROJECT_NAME_LABEL)
110
+ functions, canary = cls._resolve_canary(api_gateway.spec.upstreams)
111
+ return cls(
112
+ project=project,
113
+ description=api_gateway.spec.description,
114
+ name=api_gateway.spec.name,
115
+ host=api_gateway.spec.host,
116
+ path=api_gateway.spec.path,
117
+ authentication_mode=str(api_gateway.spec.authenticationMode),
118
+ functions=functions,
119
+ canary=canary,
120
+ )
121
+
122
+ def to_scheme(self) -> mlrun.common.schemas.APIGateway:
123
+ upstreams = (
124
+ [
125
+ mlrun.common.schemas.APIGatewayUpstream(
126
+ nucliofunction={"name": function_name},
127
+ percentage=percentage,
128
+ )
129
+ for function_name, percentage in zip(self.functions, self.canary)
130
+ ]
131
+ if self.canary
132
+ else [
133
+ mlrun.common.schemas.APIGatewayUpstream(
134
+ nucliofunction={"name": function_name},
135
+ )
136
+ for function_name in self.functions
137
+ ]
138
+ )
139
+ api_gateway = mlrun.common.schemas.APIGateway(
140
+ metadata=mlrun.common.schemas.APIGatewayMetadata(name=self.name, labels={}),
141
+ spec=mlrun.common.schemas.APIGatewaySpec(
142
+ name=self.name,
143
+ description=self.description,
144
+ path=self.path,
145
+ authentication_mode=mlrun.common.schemas.APIGatewayAuthenticationMode.from_str(
146
+ self.authentication_mode
147
+ ),
148
+ upstreams=upstreams,
149
+ ),
150
+ )
151
+ if (
152
+ self.authentication_mode
153
+ is NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
154
+ ):
155
+ api_gateway.spec.authentication = mlrun.common.schemas.APIGatewayBasicAuth(
156
+ username=self._username, password=self._password
157
+ )
158
+ return api_gateway
159
+
160
+ @property
161
+ def invoke_url(
162
+ self,
163
+ ):
164
+ return urljoin(self.host, self.path)
165
+
166
+ def _validate(
167
+ self,
168
+ name: str,
169
+ project: str,
170
+ functions: Union[
171
+ list[str],
172
+ Union[
173
+ list[
174
+ Union[
175
+ RemoteRuntime,
176
+ ServingRuntime,
177
+ ]
178
+ ],
179
+ Union[RemoteRuntime, ServingRuntime],
180
+ ],
181
+ ],
182
+ canary: Optional[list[int]] = None,
183
+ username: Optional[str] = None,
184
+ password: Optional[str] = None,
185
+ ):
186
+ if not name:
187
+ raise mlrun.errors.MLRunInvalidArgumentError(
188
+ "API Gateway name cannot be empty"
189
+ )
190
+
191
+ self.functions = self._validate_functions(project=project, functions=functions)
192
+
193
+ # validating canary
194
+ if canary:
195
+ if len(self.functions) != len(canary):
196
+ raise mlrun.errors.MLRunInvalidArgumentError(
197
+ "Function and canary lists lengths do not match"
198
+ )
199
+ for canary_percent in canary:
200
+ if canary_percent < 0 or canary_percent > 100:
201
+ raise mlrun.errors.MLRunInvalidArgumentError(
202
+ "The percentage value must be in the range from 0 to 100"
203
+ )
204
+ if sum(canary) != 100:
205
+ raise mlrun.errors.MLRunInvalidArgumentError(
206
+ "The sum of canary function percents should be equal to 100"
207
+ )
208
+
209
+ # validating auth
210
+ if username and not password:
211
+ raise mlrun.errors.MLRunInvalidArgumentError("Password is not specified")
212
+
213
+ if password and not username:
214
+ raise mlrun.errors.MLRunInvalidArgumentError("Username is not specified")
215
+
216
+ @staticmethod
217
+ def _validate_functions(
218
+ project: str,
219
+ functions: Union[
220
+ list[str],
221
+ Union[
222
+ list[
223
+ Union[
224
+ RemoteRuntime,
225
+ ServingRuntime,
226
+ ]
227
+ ],
228
+ Union[RemoteRuntime, ServingRuntime],
229
+ ],
230
+ ],
231
+ ):
232
+ if not isinstance(functions, list):
233
+ functions = [functions]
234
+
235
+ # validating functions
236
+ if not 1 <= len(functions) <= 2:
237
+ raise mlrun.errors.MLRunInvalidArgumentError(
238
+ f"Gateway can be created from one or two functions, "
239
+ f"the number of functions passed is {len(functions)}"
240
+ )
241
+
242
+ function_names = []
243
+ for func in functions:
244
+ if isinstance(func, str):
245
+ function_names.append(func)
246
+ continue
247
+
248
+ function_name = (
249
+ func.metadata.name if hasattr(func, "metadata") else func.name
250
+ )
251
+ if func.kind not in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
252
+ raise mlrun.errors.MLRunInvalidArgumentError(
253
+ f"Input function {function_name} is not a Nuclio function"
254
+ )
255
+ if func.metadata.project != project:
256
+ raise mlrun.errors.MLRunInvalidArgumentError(
257
+ f"input function {function_name} "
258
+ f"does not belong to this project"
259
+ )
260
+ function_names.append(func.uri)
261
+ return function_names
262
+
263
+ @staticmethod
264
+ def _enrich_authentication_mode(username, password):
265
+ return (
266
+ NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE
267
+ if username is not None and password is not None
268
+ else NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
269
+ )
270
+
271
+ @staticmethod
272
+ def _generate_basic_auth(username: str, password: str):
273
+ token = base64.b64encode(f"{username}:{password}".encode()).decode()
274
+ return f"Basic {token}"
275
+
276
+ @staticmethod
277
+ def _resolve_canary(
278
+ upstreams: list[mlrun.common.schemas.APIGatewayUpstream],
279
+ ) -> tuple[Union[list[str], None], Union[list[int], None]]:
280
+ if len(upstreams) == 1:
281
+ return [upstreams[0].nucliofunction.get("name")], None
282
+ elif len(upstreams) == 2:
283
+ canary = [0, 0]
284
+ functions = [
285
+ upstreams[0].nucliofunction.get("name"),
286
+ upstreams[1].nucliofunction.get("name"),
287
+ ]
288
+ percentage_1 = upstreams[0].percentage
289
+ percentage_2 = upstreams[1].percentage
290
+
291
+ if not percentage_1 and percentage_2:
292
+ percentage_1 = 100 - percentage_2
293
+ if not percentage_2 and percentage_1:
294
+ percentage_2 = 100 - percentage_1
295
+ if percentage_1 and percentage_2:
296
+ canary = [percentage_1, percentage_2]
297
+ return functions, canary
298
+ else:
299
+ # Nuclio only supports 1 or 2 upstream functions
300
+ return None, None
mlrun/utils/logger.py CHANGED
@@ -221,7 +221,7 @@ class FormatterKinds(Enum):
221
221
  JSON = "json"
222
222
 
223
223
 
224
- def _create_formatter_instance(formatter_kind: FormatterKinds) -> logging.Formatter:
224
+ def create_formatter_instance(formatter_kind: FormatterKinds) -> logging.Formatter:
225
225
  return {
226
226
  FormatterKinds.HUMAN: HumanReadableFormatter(),
227
227
  FormatterKinds.HUMAN_EXTENDED: HumanReadableExtendedFormatter(),
@@ -243,7 +243,7 @@ def create_logger(
243
243
  logger_instance = Logger(level, name=name, propagate=False)
244
244
 
245
245
  # resolve formatter
246
- formatter_instance = _create_formatter_instance(
246
+ formatter_instance = create_formatter_instance(
247
247
  FormatterKinds(formatter_kind.lower())
248
248
  )
249
249
 
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "cb2750f25e202a321723af3465359944445dfda7",
3
- "version": "1.7.0-rc4"
2
+ "git_commit": "d3324e482f4a4182ee0c8eda4af0d312718b599d",
3
+ "version": "1.7.0-rc5"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mlrun
3
- Version: 1.7.0rc4
3
+ Version: 1.7.0rc5
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -1,6 +1,6 @@
1
1
  mlrun/__init__.py,sha256=o9dHUfVFADfsi6GnOPLr2OkfkHdPvOnA7rkoECen0-I,7248
2
2
  mlrun/__main__.py,sha256=vg-HMhJqQ3OYt31YmijjBh6-6AZQVe4FvDYn4MwEpYs,49229
3
- mlrun/config.py,sha256=xH1gK-yMe6PdUEyB2FCGfoNzDILHak_6H9J-1CdLwUg,62255
3
+ mlrun/config.py,sha256=mAhLKO6P0i8r_vGDCMNFV0cJv4Pb7mRmm9HR3rudwWI,62563
4
4
  mlrun/errors.py,sha256=HmOAdfpL0bCDisZMUoJPOumneq71ko49Ph-XBL-A4xA,7080
5
5
  mlrun/execution.py,sha256=meZ_qSdTmnpqW7DKv7LdBmuE1Ut34E1RbK2kO0MD_QM,40866
6
6
  mlrun/features.py,sha256=nPDvy8tJuxwbRr843oWcnLBrqMJDPUanzn2Sb3BBi6w,15569
@@ -9,7 +9,7 @@ mlrun/kfpops.py,sha256=nVQUjLVBhXqkL2OTWJUo4qFIfNVEXUKIXJmRpBW0MVU,30481
9
9
  mlrun/lists.py,sha256=ev-gLBPc_az03yQEHrKyDPq_Bjosa4D_XFiVbRIpmRY,8286
10
10
  mlrun/model.py,sha256=e9tJG8-wP3gPywDu7wJMNsusLTGpVA9WpBbILFwR5Ns,70583
11
11
  mlrun/render.py,sha256=aMH3U2z7ELpW8MwYEGOrqLdEUwMX29shqy6V6-KbgiM,13009
12
- mlrun/run.py,sha256=Xj9CdKuRFqMGTJ2fV2YTKFlTg45ZgYtrHx8Ooaljgek,42400
12
+ mlrun/run.py,sha256=1GZk2f3xU2OrBE4aHMzVe0RUpwc1DokWiVwdwnTszlU,42400
13
13
  mlrun/secrets.py,sha256=Nl_7ZNSErd-AOH19vVx_PjrLg9bJM9L-BvEYoPolB1c,7776
14
14
  mlrun/api/schemas/__init__.py,sha256=LhfO3myrnLVxC0MYCAc1_LTuqhRlYV3H7BwJkjOu3dQ,14211
15
15
  mlrun/artifacts/__init__.py,sha256=LxEWcMYPawJYvNOl6H2_UvrxdLTNYfKeZcMEKFZnGgA,1187
@@ -19,7 +19,7 @@ mlrun/artifacts/manager.py,sha256=p6CmIJH91vm9DsEZHgHxKYTHU2BvF9IwpLv85cqoHNs,14
19
19
  mlrun/artifacts/model.py,sha256=DXT24CH1ZgQLz9HcWBfjRAEhCBfznoa7-pB52N9qMOI,25205
20
20
  mlrun/artifacts/plots.py,sha256=dHt7Ardo4yZWaPtlUN3b78eB8NXV8XKigPP0u0poRl0,15701
21
21
  mlrun/common/__init__.py,sha256=xY3wHC4TEJgez7qtnn1pQvHosi8-5UJOCtyGBS7FcGE,571
22
- mlrun/common/constants.py,sha256=sIec-l1aj4GHOn__iwX-2A2mbTx5YYeWMLyhMUsWNTQ,707
22
+ mlrun/common/constants.py,sha256=OwcN3HroG3l94Kx1B-247cp1UyqC0IVLc_TCFGWmrg4,745
23
23
  mlrun/common/helpers.py,sha256=BAhyuUnZvD_BT43i0_1EszuSbKgZx7bFy2KRIWP0XeA,1087
24
24
  mlrun/common/secrets.py,sha256=vc8WV82EZsCB5ENjUkObFOzZP59aZ1w8F82PTnqwBnc,5181
25
25
  mlrun/common/types.py,sha256=V_jCEFCJZcycFVsPzEToCRQja5bqW0zRAAVaGN_QYxQ,790
@@ -27,9 +27,10 @@ mlrun/common/db/__init__.py,sha256=xY3wHC4TEJgez7qtnn1pQvHosi8-5UJOCtyGBS7FcGE,5
27
27
  mlrun/common/db/sql_session.py,sha256=Znc8KE2oLy4lg3_vRki1sVlNx59TgDSOTCXfU561hBU,2659
28
28
  mlrun/common/model_monitoring/__init__.py,sha256=x0EMEvxVjHsm858J1t6IEA9dtKTdFpJ9sKhss10ld8A,721
29
29
  mlrun/common/model_monitoring/helpers.py,sha256=1CpxIDQPumFnpUB1eqcvCpLlyPFVeW2sL6prM-N5A1A,4405
30
- mlrun/common/schemas/__init__.py,sha256=JZZB7i513MJZUYQgEJ5KxMlTyEfvJJvWKyHB25meS5E,4718
30
+ mlrun/common/schemas/__init__.py,sha256=PKOeaerKRHOIWCmaIhCYdlieOZhZDDf8cubNOWlJQaM,4935
31
+ mlrun/common/schemas/api_gateway.py,sha256=lDXnA0mE9PCyeB0p7VSoj7TN0xSF-e6XUrTYJjLqbbQ,2344
31
32
  mlrun/common/schemas/artifact.py,sha256=d6srME_eWn2MpGuqvPQZtePRFkjDfNJgQ6JDd51qVrI,2796
32
- mlrun/common/schemas/auth.py,sha256=4aiaBy-g8iDQo41_9FQydI49Onak6j4PNsmI79s-vT4,5957
33
+ mlrun/common/schemas/auth.py,sha256=KOQfABIXTrcMh3Us5vlmnN4w3bJB7Rl3Xd5GTAFpr-g,5970
33
34
  mlrun/common/schemas/background_task.py,sha256=2qZxib2qrF_nPZj0ncitCG-2jxz2hg1qj0hFc8eswWQ,1707
34
35
  mlrun/common/schemas/client_spec.py,sha256=EFYUSstblo13-O0LTwJfnsYmxbGPAypY3idy8SHpq1c,2858
35
36
  mlrun/common/schemas/clusterization_spec.py,sha256=aeaFJZms7r7h2HDv6ML_GDAT6gboW-PxBbc3GKPalGk,888
@@ -81,16 +82,16 @@ mlrun/datastore/sources.py,sha256=6rK3pmpQ0Mzk1p3yEvMSqiaJOpjXGsMpXOcDYlcHaP8,40
81
82
  mlrun/datastore/spark_udf.py,sha256=NnnB3DZxZb-rqpRy7b-NC7QWXuuqFn3XkBDc86tU4mQ,1498
82
83
  mlrun/datastore/spark_utils.py,sha256=50rllp6xXpXY__1LbU7aTXUU5ca8dKAfoskPre3npZo,1611
83
84
  mlrun/datastore/store_resources.py,sha256=dfMdFy2urilECtlwLJr5CSG12MA645b-NPYDnbr5s1A,6839
84
- mlrun/datastore/targets.py,sha256=Hei-PlXmNpbb9IJ0LOz7gGarvXoD2ca46r_47V3O9Y8,70653
85
+ mlrun/datastore/targets.py,sha256=YjjvXnaEEj0ojxiOxoRSuIrbzAvuRSpFxX-9_zJFaZ0,70714
85
86
  mlrun/datastore/utils.py,sha256=YKK9q1C0LmveQFnbh1Dkb8LwA4WbOYFTsNxziC8d0E4,5227
86
87
  mlrun/datastore/v3io.py,sha256=oCAMpST6sKnjm5CaNsTrcwqk3bvUFzuKBvNFmUJpPfw,9252
87
88
  mlrun/datastore/wasbfs/__init__.py,sha256=s5Ul-0kAhYqFjKDR2X0O2vDGDbLQQduElb32Ev56Te4,1343
88
89
  mlrun/datastore/wasbfs/fs.py,sha256=MnSj7Q4OKA2L55ihCmUnj2t3GA3B77oLMdAw-yxvN9w,6151
89
90
  mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
90
- mlrun/db/base.py,sha256=exhNorDB-wxRq0yRUj-cXe5NUB1hR6fe7p9grvw3sWc,18505
91
+ mlrun/db/base.py,sha256=d6J2g2uFvJh8CcAYoFR4DxPvKsAjByKxLqGENWDoluc,18906
91
92
  mlrun/db/factory.py,sha256=wTEKHEmdDkylM6IkTYvmEYVF8gn2HdjLoLoWICCyatI,2403
92
- mlrun/db/httpdb.py,sha256=pljaKPnFAPX4zuDHl8KcQ8-nkR-KLrEW9bcXFws4LbE,156837
93
- mlrun/db/nopdb.py,sha256=7SnfMdusNvtxM0GmFIYLCBnkB-fSnvUtM2hQoF1q--I,14514
93
+ mlrun/db/httpdb.py,sha256=JtVbbetPzhpZNYb5meXMevPIRGkGu2KBbb9QTADYvLs,158600
94
+ mlrun/db/nopdb.py,sha256=FoEFMfnh1aSs-mcXlwA8GnnbQCIoTtFkflbFpUF5bMY,14814
94
95
  mlrun/feature_store/__init__.py,sha256=n1F5m1svFW2chbE2dJdWzZJJiYS4E-y8PQsG9Q-F0lU,1584
95
96
  mlrun/feature_store/api.py,sha256=bO5I_lkIPLv8j3AXYOAseSBI8RrsGwQ9m7isepuADkw,49480
96
97
  mlrun/feature_store/common.py,sha256=DKmoRk04NCS1gv7qZuEUa2-g8WsfR6IWjYctcrqKVlg,12853
@@ -245,9 +246,9 @@ mlrun/platforms/other.py,sha256=T1BibmEBNggM62YJ6oejRmcVv_1besfH5DDHhCaDkRg,1182
245
246
  mlrun/projects/__init__.py,sha256=Lv5rfxyXJrw6WGOWJKhBz66M6t3_zsNMCfUD6waPwx4,1153
246
247
  mlrun/projects/operations.py,sha256=SiDHd7cqh9u23AVpETbkJE6WmOnB434zBrwM-StZLQY,18538
247
248
  mlrun/projects/pipelines.py,sha256=SMXBmIeuopwPpU0o2VFvaPXgbmaj-2WfCJryN6mZvZY,40124
248
- mlrun/projects/project.py,sha256=fRsf7dVj9F9jpVqp7bnQ7B5fNAFY-tAcpwgMWtkuq_w,155594
249
+ mlrun/projects/project.py,sha256=7BJwLO9pdEfrP55Ppf2z3nLOQ_gPWQIhgt_pZvqKtm4,158052
249
250
  mlrun/runtimes/__init__.py,sha256=vsoNA9ts_VPvGN9YPYKAjkxZe1RaZu22D5t-tiMyP-4,7034
250
- mlrun/runtimes/base.py,sha256=G0OtEBza6I_6AwQPA-k4XhNkbboxwf9g3Q56kowl1V4,36355
251
+ mlrun/runtimes/base.py,sha256=Faxa44TFCu7xA3UzYl36u1ZMpITJpTkiFJ7j-oRhJVA,36562
251
252
  mlrun/runtimes/constants.py,sha256=oP3OxdYCpbvadJ3zP1JGkqGBKaBheNkCnJISWha9x58,9513
252
253
  mlrun/runtimes/daskjob.py,sha256=xvN8ajs3-_voqxrfz6b3rh_idNw4ypRAkPRWGOnDMGA,19149
253
254
  mlrun/runtimes/funcdoc.py,sha256=FHwnLfFzoD6yGlsAJXAl_3VTtudgg4fTrsw_XqLOkC0,10508
@@ -266,7 +267,8 @@ mlrun/runtimes/mpijob/__init__.py,sha256=jZf2uPBv6IB18Jj-dGSQ9NU5_xxni7XS4dnDZGw
266
267
  mlrun/runtimes/mpijob/abstract.py,sha256=AqIb-nEKZaRO7x1GxJea6cXg_Tn3Dr4WiWZUz3ywCjU,9161
267
268
  mlrun/runtimes/mpijob/v1.py,sha256=_RUlFo_3NcFf7x-QpUNVm8f7qNbRDIdUmPf_ijrv54U,3206
268
269
  mlrun/runtimes/mpijob/v1alpha1.py,sha256=w_971wwL03hW_ksgHJXdjTdjhxCs9KJ0zNqHSQ9whIM,1034
269
- mlrun/runtimes/nuclio/__init__.py,sha256=5V9oUtyU058xH_n9CiAXWDZJuipTyG3I1RGhBTt7T_0,758
270
+ mlrun/runtimes/nuclio/__init__.py,sha256=gx1kizzKv8pGT5TNloN1js1hdbxqDw3rM90sLVYVffY,794
271
+ mlrun/runtimes/nuclio/api_gateway.py,sha256=t4im6F8f-zPYYXrHXCFr46Rw6sGgvydIpxpgxncTUMQ,10277
270
272
  mlrun/runtimes/nuclio/function.py,sha256=glnE8K-4rQVfQB2hCeLt8OtcpG2NFwKgEB8aRClcSJ4,47402
271
273
  mlrun/runtimes/nuclio/nuclio.py,sha256=sLK8KdGO1LbftlL3HqPZlFOFTAAuxJACZCVl1c0Ha6E,2942
272
274
  mlrun/runtimes/nuclio/serving.py,sha256=hzkXKCVgU6uXLYfO3H15ZWJIQiSbcKY2M_WLybHW1hM,30363
@@ -295,7 +297,7 @@ mlrun/utils/condition_evaluator.py,sha256=-nGfRmZzivn01rHTroiGY4rqEv8T1irMyhzxEe
295
297
  mlrun/utils/db.py,sha256=KEa-vzicUhzIwo1wBXax2ZuXtYgf5to7wnsY3CYCiOQ,1713
296
298
  mlrun/utils/helpers.py,sha256=guQSdMvQT8KdS2_LHXe0C9pTEC56XtsWNMliSI0i5CQ,51162
297
299
  mlrun/utils/http.py,sha256=mQqnCsdsg9_q2WIbgoEKGQpMesslb0ErvbwYV-htarw,8700
298
- mlrun/utils/logger.py,sha256=MCj18mxDbDV86CV_R2l7_8PoAWZPU-GtmkSbWFkss4w,8135
300
+ mlrun/utils/logger.py,sha256=6-XMv1ucg9NqTstLpiji9qb06XHpx2LvNA8JxU1J5Tk,8133
299
301
  mlrun/utils/regex.py,sha256=Nd7xnDHU9PEOsse6rFwLNVgU4AaYCyuwMmQ9qgx2-Vw,4581
300
302
  mlrun/utils/retryer.py,sha256=BsST2dbGCHcY46wyGG3zWel_O9YquO0c57P3rcBxXU0,7522
301
303
  mlrun/utils/singleton.py,sha256=p1Y-X0mPSs_At092GS-pZCA8CTR62HOqPU07_ZH6-To,869
@@ -311,11 +313,11 @@ mlrun/utils/notifications/notification/ipython.py,sha256=d47s-fW4TgqOJZOSdmzBQvd
311
313
  mlrun/utils/notifications/notification/slack.py,sha256=5JysqIpUYUZKXPSeeZtbl7qb2L9dj7p2NvnEBcEsZkA,3898
312
314
  mlrun/utils/notifications/notification/webhook.py,sha256=QHezCuN5uXkLcroAGxGrhGHaxAdUvkDLIsp27_Yrfd4,2390
313
315
  mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
314
- mlrun/utils/version/version.json,sha256=gHF4gBcfnBuVhOFzc6eGMjVwEIMbyScdRcHadPcGqMA,88
316
+ mlrun/utils/version/version.json,sha256=ZRswxH-AwVSByZa3TM00R47LdOv7o0_cYL3CzdifHz0,88
315
317
  mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
316
- mlrun-1.7.0rc4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
317
- mlrun-1.7.0rc4.dist-info/METADATA,sha256=cK98mzAZ6SZp3vGbvlgSuC72lt064HWhDulfYclg04Y,18263
318
- mlrun-1.7.0rc4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
319
- mlrun-1.7.0rc4.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
320
- mlrun-1.7.0rc4.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
321
- mlrun-1.7.0rc4.dist-info/RECORD,,
318
+ mlrun-1.7.0rc5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
319
+ mlrun-1.7.0rc5.dist-info/METADATA,sha256=_bRlth3i1-0z_O8MHjRjyJPFlevk6zBa_kGp53B3mOE,18263
320
+ mlrun-1.7.0rc5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
321
+ mlrun-1.7.0rc5.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
322
+ mlrun-1.7.0rc5.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
323
+ mlrun-1.7.0rc5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5