mlrun 1.3.3rc1__py3-none-any.whl → 1.4.0__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/__init__.py +3 -3
- mlrun/__main__.py +79 -37
- mlrun/api/__init__.py +1 -1
- mlrun/api/api/__init__.py +1 -1
- mlrun/api/api/api.py +4 -4
- mlrun/api/api/deps.py +10 -21
- mlrun/api/api/endpoints/__init__.py +1 -1
- mlrun/api/api/endpoints/artifacts.py +64 -36
- mlrun/api/api/endpoints/auth.py +4 -4
- mlrun/api/api/endpoints/background_tasks.py +11 -11
- mlrun/api/api/endpoints/client_spec.py +5 -5
- mlrun/api/api/endpoints/clusterization_spec.py +6 -4
- mlrun/api/api/endpoints/feature_store.py +124 -115
- mlrun/api/api/endpoints/files.py +22 -14
- mlrun/api/api/endpoints/frontend_spec.py +28 -21
- mlrun/api/api/endpoints/functions.py +142 -87
- mlrun/api/api/endpoints/grafana_proxy.py +89 -442
- mlrun/api/api/endpoints/healthz.py +20 -7
- mlrun/api/api/endpoints/hub.py +320 -0
- mlrun/api/api/endpoints/internal/__init__.py +1 -1
- mlrun/api/api/endpoints/internal/config.py +1 -1
- mlrun/api/api/endpoints/internal/memory_reports.py +9 -9
- mlrun/api/api/endpoints/logs.py +11 -11
- mlrun/api/api/endpoints/model_endpoints.py +74 -70
- mlrun/api/api/endpoints/operations.py +13 -9
- mlrun/api/api/endpoints/pipelines.py +93 -88
- mlrun/api/api/endpoints/projects.py +35 -35
- mlrun/api/api/endpoints/runs.py +69 -27
- mlrun/api/api/endpoints/runtime_resources.py +28 -28
- mlrun/api/api/endpoints/schedules.py +98 -41
- mlrun/api/api/endpoints/secrets.py +37 -32
- mlrun/api/api/endpoints/submit.py +12 -12
- mlrun/api/api/endpoints/tags.py +20 -22
- mlrun/api/api/utils.py +251 -42
- mlrun/api/constants.py +1 -1
- mlrun/api/crud/__init__.py +18 -15
- mlrun/api/crud/artifacts.py +10 -10
- mlrun/api/crud/client_spec.py +4 -4
- mlrun/api/crud/clusterization_spec.py +3 -3
- mlrun/api/crud/feature_store.py +54 -46
- mlrun/api/crud/functions.py +3 -3
- mlrun/api/crud/hub.py +312 -0
- mlrun/api/crud/logs.py +11 -9
- mlrun/api/crud/model_monitoring/__init__.py +3 -3
- mlrun/api/crud/model_monitoring/grafana.py +435 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +352 -129
- mlrun/api/crud/notifications.py +149 -0
- mlrun/api/crud/pipelines.py +67 -52
- mlrun/api/crud/projects.py +51 -23
- mlrun/api/crud/runs.py +7 -5
- mlrun/api/crud/runtime_resources.py +13 -13
- mlrun/api/{db/filedb → crud/runtimes}/__init__.py +1 -1
- mlrun/api/crud/runtimes/nuclio/__init__.py +14 -0
- mlrun/api/crud/runtimes/nuclio/function.py +505 -0
- mlrun/api/crud/runtimes/nuclio/helpers.py +310 -0
- mlrun/api/crud/secrets.py +88 -46
- mlrun/api/crud/tags.py +5 -5
- mlrun/api/db/__init__.py +1 -1
- mlrun/api/db/base.py +102 -54
- mlrun/api/db/init_db.py +2 -3
- mlrun/api/db/session.py +4 -12
- mlrun/api/db/sqldb/__init__.py +1 -1
- mlrun/api/db/sqldb/db.py +439 -196
- mlrun/api/db/sqldb/helpers.py +1 -1
- mlrun/api/db/sqldb/models/__init__.py +3 -3
- mlrun/api/db/sqldb/models/models_mysql.py +82 -64
- mlrun/api/db/sqldb/models/models_sqlite.py +76 -64
- mlrun/api/db/sqldb/session.py +27 -20
- mlrun/api/initial_data.py +82 -24
- mlrun/api/launcher.py +196 -0
- mlrun/api/main.py +91 -22
- mlrun/api/middlewares.py +6 -5
- mlrun/api/migrations_mysql/env.py +1 -1
- mlrun/api/migrations_mysql/versions/28383af526f3_market_place_to_hub.py +40 -0
- mlrun/api/migrations_mysql/versions/32bae1b0e29c_increase_timestamp_fields_precision.py +1 -1
- mlrun/api/migrations_mysql/versions/4903aef6a91d_tag_foreign_key_and_cascades.py +1 -1
- mlrun/api/migrations_mysql/versions/5f1351c88a19_adding_background_tasks_table.py +1 -1
- mlrun/api/migrations_mysql/versions/88e656800d6a_add_requested_logs_column_and_index_to_.py +1 -1
- mlrun/api/migrations_mysql/versions/9d16de5f03a7_adding_data_versions_table.py +1 -1
- mlrun/api/migrations_mysql/versions/b86f5b53f3d7_adding_name_and_updated_to_runs_table.py +1 -1
- mlrun/api/migrations_mysql/versions/c4af40b0bf61_init.py +1 -1
- mlrun/api/migrations_mysql/versions/c905d15bd91d_notifications.py +72 -0
- mlrun/api/migrations_mysql/versions/ee041e8fdaa0_adding_next_run_time_column_to_schedule_.py +1 -1
- mlrun/api/migrations_sqlite/env.py +1 -1
- mlrun/api/migrations_sqlite/versions/11f8dd2dc9fe_init.py +1 -1
- mlrun/api/migrations_sqlite/versions/1c954f8cb32d_schedule_last_run_uri.py +1 -1
- mlrun/api/migrations_sqlite/versions/2b6d23c715aa_adding_feature_sets.py +1 -1
- mlrun/api/migrations_sqlite/versions/4acd9430b093_market_place_to_hub.py +77 -0
- mlrun/api/migrations_sqlite/versions/6401142f2d7c_adding_next_run_time_column_to_schedule_.py +1 -1
- mlrun/api/migrations_sqlite/versions/64d90a1a69bc_adding_background_tasks_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/803438ecd005_add_requested_logs_column_to_runs.py +1 -1
- mlrun/api/migrations_sqlite/versions/863114f0c659_refactoring_feature_set.py +1 -1
- mlrun/api/migrations_sqlite/versions/959ae00528ad_notifications.py +63 -0
- mlrun/api/migrations_sqlite/versions/accf9fc83d38_adding_data_versions_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/b68e8e897a28_schedule_labels.py +1 -1
- mlrun/api/migrations_sqlite/versions/bcd0c1f9720c_adding_project_labels.py +1 -1
- mlrun/api/migrations_sqlite/versions/cf21882f938e_schedule_id.py +1 -1
- mlrun/api/migrations_sqlite/versions/d781f58f607f_tag_object_name_string.py +1 -1
- mlrun/api/migrations_sqlite/versions/deac06871ace_adding_marketplace_sources_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/e1dd5983c06b_schedule_concurrency_limit.py +1 -1
- mlrun/api/migrations_sqlite/versions/e5594ed3ab53_adding_name_and_updated_to_runs_table.py +1 -1
- mlrun/api/migrations_sqlite/versions/f4249b4ba6fa_adding_feature_vectors.py +1 -1
- mlrun/api/migrations_sqlite/versions/f7b5a1a03629_adding_feature_labels.py +1 -1
- mlrun/api/schemas/__init__.py +216 -138
- mlrun/api/utils/__init__.py +1 -1
- mlrun/api/utils/asyncio.py +1 -1
- mlrun/api/utils/auth/__init__.py +1 -1
- mlrun/api/utils/auth/providers/__init__.py +1 -1
- mlrun/api/utils/auth/providers/base.py +7 -7
- mlrun/api/utils/auth/providers/nop.py +6 -7
- mlrun/api/utils/auth/providers/opa.py +17 -17
- mlrun/api/utils/auth/verifier.py +36 -34
- mlrun/api/utils/background_tasks.py +24 -24
- mlrun/{builder.py → api/utils/builder.py} +216 -123
- mlrun/api/utils/clients/__init__.py +1 -1
- mlrun/api/utils/clients/chief.py +19 -4
- mlrun/api/utils/clients/iguazio.py +106 -60
- mlrun/api/utils/clients/log_collector.py +1 -1
- mlrun/api/utils/clients/nuclio.py +23 -23
- mlrun/api/utils/clients/protocols/grpc.py +2 -2
- mlrun/api/utils/db/__init__.py +1 -1
- mlrun/api/utils/db/alembic.py +1 -1
- mlrun/api/utils/db/backup.py +1 -1
- mlrun/api/utils/db/mysql.py +24 -25
- mlrun/api/utils/db/sql_collation.py +1 -1
- mlrun/api/utils/db/sqlite_migration.py +2 -2
- mlrun/api/utils/events/__init__.py +14 -0
- mlrun/api/utils/events/base.py +57 -0
- mlrun/api/utils/events/events_factory.py +41 -0
- mlrun/api/utils/events/iguazio.py +217 -0
- mlrun/api/utils/events/nop.py +55 -0
- mlrun/api/utils/helpers.py +16 -13
- mlrun/api/utils/memory_reports.py +1 -1
- mlrun/api/utils/periodic.py +6 -3
- mlrun/api/utils/projects/__init__.py +1 -1
- mlrun/api/utils/projects/follower.py +33 -33
- mlrun/api/utils/projects/leader.py +36 -34
- mlrun/api/utils/projects/member.py +27 -27
- mlrun/api/utils/projects/remotes/__init__.py +1 -1
- mlrun/api/utils/projects/remotes/follower.py +13 -13
- mlrun/api/utils/projects/remotes/leader.py +10 -10
- mlrun/api/utils/projects/remotes/nop_follower.py +27 -21
- mlrun/api/utils/projects/remotes/nop_leader.py +17 -16
- mlrun/api/utils/scheduler.py +140 -51
- mlrun/api/utils/singletons/__init__.py +1 -1
- mlrun/api/utils/singletons/db.py +9 -15
- mlrun/api/utils/singletons/k8s.py +677 -5
- mlrun/api/utils/singletons/logs_dir.py +1 -1
- mlrun/api/utils/singletons/project_member.py +1 -1
- mlrun/api/utils/singletons/scheduler.py +1 -1
- mlrun/artifacts/__init__.py +2 -2
- mlrun/artifacts/base.py +8 -2
- mlrun/artifacts/dataset.py +5 -3
- mlrun/artifacts/manager.py +7 -1
- mlrun/artifacts/model.py +15 -4
- mlrun/artifacts/plots.py +1 -1
- mlrun/common/__init__.py +1 -1
- mlrun/common/constants.py +15 -0
- mlrun/common/model_monitoring.py +209 -0
- mlrun/common/schemas/__init__.py +167 -0
- mlrun/{api → common}/schemas/artifact.py +13 -14
- mlrun/{api → common}/schemas/auth.py +10 -8
- mlrun/{api → common}/schemas/background_task.py +3 -3
- mlrun/{api → common}/schemas/client_spec.py +1 -1
- mlrun/{api → common}/schemas/clusterization_spec.py +3 -3
- mlrun/{api → common}/schemas/constants.py +21 -8
- mlrun/common/schemas/events.py +36 -0
- mlrun/{api → common}/schemas/feature_store.py +2 -1
- mlrun/{api → common}/schemas/frontend_spec.py +7 -6
- mlrun/{api → common}/schemas/function.py +5 -5
- mlrun/{api → common}/schemas/http.py +3 -3
- mlrun/common/schemas/hub.py +134 -0
- mlrun/{api → common}/schemas/k8s.py +3 -3
- mlrun/{api → common}/schemas/memory_reports.py +1 -1
- mlrun/common/schemas/model_endpoints.py +342 -0
- mlrun/common/schemas/notification.py +57 -0
- mlrun/{api → common}/schemas/object.py +6 -6
- mlrun/{api → common}/schemas/pipeline.py +3 -3
- mlrun/{api → common}/schemas/project.py +6 -5
- mlrun/common/schemas/regex.py +24 -0
- mlrun/common/schemas/runs.py +30 -0
- mlrun/{api → common}/schemas/runtime_resource.py +3 -3
- mlrun/{api → common}/schemas/schedule.py +19 -7
- mlrun/{api → common}/schemas/secret.py +3 -3
- mlrun/{api → common}/schemas/tag.py +2 -2
- mlrun/common/types.py +25 -0
- mlrun/config.py +152 -20
- mlrun/data_types/__init__.py +7 -2
- mlrun/data_types/data_types.py +4 -2
- mlrun/data_types/infer.py +1 -1
- mlrun/data_types/spark.py +10 -3
- mlrun/datastore/__init__.py +10 -3
- mlrun/datastore/azure_blob.py +1 -1
- mlrun/datastore/base.py +185 -53
- mlrun/datastore/datastore.py +1 -1
- mlrun/datastore/filestore.py +1 -1
- mlrun/datastore/google_cloud_storage.py +1 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +1 -1
- mlrun/datastore/s3.py +1 -1
- mlrun/datastore/sources.py +192 -70
- mlrun/datastore/spark_udf.py +44 -0
- mlrun/datastore/store_resources.py +4 -4
- mlrun/datastore/targets.py +115 -45
- mlrun/datastore/utils.py +127 -5
- mlrun/datastore/v3io.py +1 -1
- mlrun/datastore/wasbfs/__init__.py +1 -1
- mlrun/datastore/wasbfs/fs.py +1 -1
- mlrun/db/__init__.py +7 -5
- mlrun/db/base.py +112 -68
- mlrun/db/httpdb.py +445 -277
- mlrun/db/nopdb.py +491 -0
- mlrun/db/sqldb.py +112 -65
- mlrun/errors.py +6 -1
- mlrun/execution.py +44 -22
- mlrun/feature_store/__init__.py +1 -1
- mlrun/feature_store/api.py +143 -95
- mlrun/feature_store/common.py +16 -20
- mlrun/feature_store/feature_set.py +42 -12
- mlrun/feature_store/feature_vector.py +32 -21
- mlrun/feature_store/ingestion.py +9 -12
- mlrun/feature_store/retrieval/__init__.py +3 -2
- mlrun/feature_store/retrieval/base.py +388 -66
- mlrun/feature_store/retrieval/dask_merger.py +63 -151
- mlrun/feature_store/retrieval/job.py +30 -12
- mlrun/feature_store/retrieval/local_merger.py +40 -133
- mlrun/feature_store/retrieval/spark_merger.py +129 -127
- mlrun/feature_store/retrieval/storey_merger.py +173 -0
- mlrun/feature_store/steps.py +132 -15
- mlrun/features.py +8 -3
- mlrun/frameworks/__init__.py +1 -1
- mlrun/frameworks/_common/__init__.py +1 -1
- mlrun/frameworks/_common/artifacts_library.py +1 -1
- mlrun/frameworks/_common/mlrun_interface.py +1 -1
- mlrun/frameworks/_common/model_handler.py +1 -1
- mlrun/frameworks/_common/plan.py +1 -1
- mlrun/frameworks/_common/producer.py +1 -1
- mlrun/frameworks/_common/utils.py +1 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -1
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -1
- mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +1 -1
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +1 -1
- mlrun/frameworks/_dl_common/model_handler.py +1 -1
- mlrun/frameworks/_dl_common/utils.py +1 -1
- mlrun/frameworks/_ml_common/__init__.py +1 -1
- mlrun/frameworks/_ml_common/artifacts_library.py +1 -1
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -1
- mlrun/frameworks/_ml_common/loggers/logger.py +1 -1
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
- mlrun/frameworks/_ml_common/model_handler.py +1 -1
- mlrun/frameworks/_ml_common/pkl_model_server.py +13 -1
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -1
- mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +1 -6
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +1 -1
- mlrun/frameworks/_ml_common/producer.py +1 -1
- mlrun/frameworks/_ml_common/utils.py +1 -1
- mlrun/frameworks/auto_mlrun/__init__.py +1 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +1 -1
- mlrun/frameworks/huggingface/__init__.py +1 -1
- mlrun/frameworks/huggingface/model_server.py +1 -1
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +1 -1
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +1 -1
- mlrun/frameworks/lgbm/mlrun_interfaces/model_mlrun_interface.py +1 -1
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/lgbm/model_server.py +1 -1
- mlrun/frameworks/lgbm/utils.py +1 -1
- mlrun/frameworks/onnx/__init__.py +1 -1
- mlrun/frameworks/onnx/dataset.py +1 -1
- mlrun/frameworks/onnx/mlrun_interface.py +1 -1
- mlrun/frameworks/onnx/model_handler.py +1 -1
- mlrun/frameworks/onnx/model_server.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +1 -1
- mlrun/frameworks/pytorch/__init__.py +1 -1
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -1
- mlrun/frameworks/pytorch/callbacks/callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +1 -1
- mlrun/frameworks/pytorch/callbacks_handler.py +1 -1
- mlrun/frameworks/pytorch/mlrun_interface.py +1 -1
- mlrun/frameworks/pytorch/model_handler.py +1 -1
- mlrun/frameworks/pytorch/model_server.py +1 -1
- mlrun/frameworks/pytorch/utils.py +1 -1
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/sklearn/estimator.py +1 -1
- mlrun/frameworks/sklearn/metric.py +1 -1
- mlrun/frameworks/sklearn/metrics_library.py +1 -1
- mlrun/frameworks/sklearn/mlrun_interface.py +1 -1
- mlrun/frameworks/sklearn/model_handler.py +1 -1
- mlrun/frameworks/sklearn/utils.py +1 -1
- mlrun/frameworks/tf_keras/__init__.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +1 -1
- mlrun/frameworks/tf_keras/model_handler.py +1 -1
- mlrun/frameworks/tf_keras/model_server.py +1 -1
- mlrun/frameworks/tf_keras/utils.py +1 -1
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/frameworks/xgboost/mlrun_interface.py +1 -1
- mlrun/frameworks/xgboost/model_handler.py +1 -1
- mlrun/frameworks/xgboost/utils.py +1 -1
- mlrun/k8s_utils.py +14 -765
- mlrun/kfpops.py +14 -17
- mlrun/launcher/__init__.py +13 -0
- mlrun/launcher/base.py +406 -0
- mlrun/launcher/client.py +159 -0
- mlrun/launcher/factory.py +50 -0
- mlrun/launcher/local.py +276 -0
- mlrun/launcher/remote.py +178 -0
- mlrun/lists.py +10 -2
- mlrun/mlutils/__init__.py +1 -1
- mlrun/mlutils/data.py +1 -1
- mlrun/mlutils/models.py +1 -1
- mlrun/mlutils/plots.py +1 -1
- mlrun/model.py +252 -14
- mlrun/model_monitoring/__init__.py +41 -0
- mlrun/model_monitoring/features_drift_table.py +1 -1
- mlrun/model_monitoring/helpers.py +123 -38
- mlrun/model_monitoring/model_endpoint.py +144 -0
- mlrun/model_monitoring/model_monitoring_batch.py +310 -259
- mlrun/model_monitoring/stores/__init__.py +106 -0
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +448 -0
- mlrun/model_monitoring/stores/model_endpoint_store.py +147 -0
- mlrun/model_monitoring/stores/models/__init__.py +23 -0
- mlrun/model_monitoring/stores/models/base.py +18 -0
- mlrun/model_monitoring/stores/models/mysql.py +100 -0
- mlrun/model_monitoring/stores/models/sqlite.py +98 -0
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +370 -0
- mlrun/model_monitoring/stream_processing_fs.py +239 -271
- mlrun/package/__init__.py +163 -0
- mlrun/package/context_handler.py +325 -0
- mlrun/package/errors.py +47 -0
- mlrun/package/packager.py +298 -0
- mlrun/{runtimes/package → package/packagers}/__init__.py +3 -1
- mlrun/package/packagers/default_packager.py +422 -0
- mlrun/package/packagers/numpy_packagers.py +612 -0
- mlrun/package/packagers/pandas_packagers.py +968 -0
- mlrun/package/packagers/python_standard_library_packagers.py +616 -0
- mlrun/package/packagers_manager.py +786 -0
- mlrun/package/utils/__init__.py +53 -0
- mlrun/package/utils/_archiver.py +226 -0
- mlrun/package/utils/_formatter.py +211 -0
- mlrun/package/utils/_pickler.py +234 -0
- mlrun/package/utils/_supported_format.py +71 -0
- mlrun/package/utils/log_hint_utils.py +93 -0
- mlrun/package/utils/type_hint_utils.py +298 -0
- mlrun/platforms/__init__.py +1 -1
- mlrun/platforms/iguazio.py +34 -2
- mlrun/platforms/other.py +1 -1
- mlrun/projects/__init__.py +1 -1
- mlrun/projects/operations.py +14 -9
- mlrun/projects/pipelines.py +31 -13
- mlrun/projects/project.py +762 -238
- mlrun/render.py +49 -19
- mlrun/run.py +57 -326
- mlrun/runtimes/__init__.py +3 -9
- mlrun/runtimes/base.py +247 -784
- mlrun/runtimes/constants.py +1 -1
- mlrun/runtimes/daskjob.py +45 -41
- mlrun/runtimes/funcdoc.py +43 -7
- mlrun/runtimes/function.py +66 -656
- mlrun/runtimes/function_reference.py +1 -1
- mlrun/runtimes/generators.py +1 -1
- mlrun/runtimes/kubejob.py +99 -116
- mlrun/runtimes/local.py +59 -66
- mlrun/runtimes/mpijob/__init__.py +1 -1
- mlrun/runtimes/mpijob/abstract.py +13 -15
- mlrun/runtimes/mpijob/v1.py +3 -1
- mlrun/runtimes/mpijob/v1alpha1.py +1 -1
- mlrun/runtimes/nuclio.py +1 -1
- mlrun/runtimes/pod.py +51 -26
- mlrun/runtimes/remotesparkjob.py +3 -1
- mlrun/runtimes/serving.py +12 -4
- mlrun/runtimes/sparkjob/__init__.py +1 -2
- mlrun/runtimes/sparkjob/abstract.py +44 -31
- mlrun/runtimes/sparkjob/spark3job.py +11 -9
- mlrun/runtimes/utils.py +61 -42
- mlrun/secrets.py +16 -18
- mlrun/serving/__init__.py +3 -2
- mlrun/serving/merger.py +1 -1
- mlrun/serving/remote.py +1 -1
- mlrun/serving/routers.py +39 -42
- mlrun/serving/server.py +23 -13
- mlrun/serving/serving_wrapper.py +1 -1
- mlrun/serving/states.py +172 -39
- mlrun/serving/utils.py +1 -1
- mlrun/serving/v1_serving.py +1 -1
- mlrun/serving/v2_serving.py +29 -21
- mlrun/utils/__init__.py +1 -2
- mlrun/utils/async_http.py +8 -1
- mlrun/utils/azure_vault.py +1 -1
- mlrun/utils/clones.py +2 -2
- mlrun/utils/condition_evaluator.py +65 -0
- mlrun/utils/db.py +52 -0
- mlrun/utils/helpers.py +188 -13
- mlrun/utils/http.py +89 -54
- mlrun/utils/logger.py +48 -8
- mlrun/utils/model_monitoring.py +132 -100
- mlrun/utils/notifications/__init__.py +1 -1
- mlrun/utils/notifications/notification/__init__.py +8 -6
- mlrun/utils/notifications/notification/base.py +20 -14
- mlrun/utils/notifications/notification/console.py +7 -4
- mlrun/utils/notifications/notification/git.py +36 -19
- mlrun/utils/notifications/notification/ipython.py +10 -8
- mlrun/utils/notifications/notification/slack.py +18 -13
- mlrun/utils/notifications/notification_pusher.py +377 -56
- mlrun/utils/regex.py +6 -1
- mlrun/utils/singleton.py +1 -1
- mlrun/utils/v3io_clients.py +1 -1
- mlrun/utils/vault.py +270 -269
- mlrun/utils/version/__init__.py +1 -1
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +1 -1
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/METADATA +16 -10
- mlrun-1.4.0.dist-info/RECORD +434 -0
- mlrun/api/api/endpoints/marketplace.py +0 -257
- mlrun/api/crud/marketplace.py +0 -221
- mlrun/api/crud/model_monitoring/model_endpoint_store.py +0 -847
- mlrun/api/db/filedb/db.py +0 -518
- mlrun/api/schemas/marketplace.py +0 -128
- mlrun/api/schemas/model_endpoints.py +0 -185
- mlrun/db/filedb.py +0 -891
- mlrun/feature_store/retrieval/online.py +0 -92
- mlrun/model_monitoring/constants.py +0 -67
- mlrun/runtimes/package/context_handler.py +0 -711
- mlrun/runtimes/sparkjob/spark2job.py +0 -59
- mlrun-1.3.3rc1.dist-info/RECORD +0 -381
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/LICENSE +0 -0
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/WHEEL +0 -0
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2023 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.
|
|
@@ -12,123 +12,402 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import asyncio
|
|
16
|
+
import datetime
|
|
16
17
|
import os
|
|
17
18
|
import typing
|
|
19
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
18
20
|
|
|
21
|
+
from fastapi.concurrency import run_in_threadpool
|
|
22
|
+
|
|
23
|
+
import mlrun.api.db.base
|
|
24
|
+
import mlrun.api.db.session
|
|
25
|
+
import mlrun.common.schemas
|
|
26
|
+
import mlrun.config
|
|
19
27
|
import mlrun.lists
|
|
20
28
|
import mlrun.model
|
|
21
29
|
import mlrun.utils.helpers
|
|
30
|
+
from mlrun.utils import logger
|
|
31
|
+
from mlrun.utils.condition_evaluator import evaluate_condition_in_separate_process
|
|
22
32
|
|
|
23
|
-
from .notification import NotificationBase,
|
|
33
|
+
from .notification import NotificationBase, NotificationTypes
|
|
24
34
|
|
|
25
35
|
|
|
26
36
|
class NotificationPusher(object):
|
|
27
37
|
|
|
28
38
|
messages = {
|
|
29
|
-
"
|
|
39
|
+
"completed": "Run completed",
|
|
30
40
|
"error": "Run failed",
|
|
41
|
+
"aborted": "Run aborted",
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
def __init__(self, runs: typing.Union[mlrun.lists.RunList, list]):
|
|
34
45
|
self._runs = runs
|
|
35
|
-
self.
|
|
36
|
-
self.
|
|
46
|
+
self._sync_notifications = []
|
|
47
|
+
self._async_notifications = []
|
|
37
48
|
|
|
38
49
|
for run in self._runs:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
if isinstance(run, dict):
|
|
51
|
+
run = mlrun.model.RunObject.from_dict(run)
|
|
52
|
+
|
|
53
|
+
for notification in run.spec.notifications:
|
|
54
|
+
try:
|
|
55
|
+
notification.status = run.status.notifications.get(
|
|
56
|
+
notification.name
|
|
57
|
+
).get("status", mlrun.common.schemas.NotificationStatus.PENDING)
|
|
58
|
+
except (AttributeError, KeyError):
|
|
59
|
+
notification.status = (
|
|
60
|
+
mlrun.common.schemas.NotificationStatus.PENDING
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if self._should_notify(run, notification):
|
|
64
|
+
self._load_notification(run, notification)
|
|
65
|
+
|
|
66
|
+
def push(
|
|
67
|
+
self,
|
|
68
|
+
db: mlrun.api.db.base.DBInterface = None,
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Asynchronously push notifications for all runs in the initialized runs list (if they should be pushed).
|
|
72
|
+
When running from a sync environment, the notifications will be pushed asynchronously however the function will
|
|
73
|
+
wait for all notifications to be pushed before returning.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
if not len(self._sync_notifications) and not len(self._async_notifications):
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
def _sync_push():
|
|
80
|
+
for notification_data in self._sync_notifications:
|
|
81
|
+
self._push_notification_sync(
|
|
82
|
+
notification_data[0],
|
|
83
|
+
notification_data[1],
|
|
84
|
+
notification_data[2],
|
|
85
|
+
db,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
async def _async_push():
|
|
89
|
+
tasks = []
|
|
90
|
+
for notification_data in self._async_notifications:
|
|
91
|
+
tasks.append(
|
|
92
|
+
self._push_notification_async(
|
|
93
|
+
notification_data[0],
|
|
94
|
+
notification_data[1],
|
|
95
|
+
notification_data[2],
|
|
96
|
+
db,
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# return exceptions to "best-effort" fire all notifications
|
|
101
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
102
|
+
|
|
103
|
+
logger.debug(
|
|
104
|
+
"Pushing notifications",
|
|
105
|
+
notifications_amount=len(self._sync_notifications)
|
|
106
|
+
+ len(self._async_notifications),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# first push async notifications
|
|
110
|
+
main_event_loop = asyncio.get_event_loop()
|
|
111
|
+
if not main_event_loop.is_running():
|
|
112
|
+
# If running mlrun SDK locally (not from jupyter), there isn't necessarily an event loop.
|
|
113
|
+
# We create a new event loop and run the async push function in it.
|
|
114
|
+
main_event_loop.run_until_complete(_async_push())
|
|
115
|
+
elif mlrun.utils.helpers.is_running_in_jupyter_notebook():
|
|
116
|
+
# Running in Jupyter notebook.
|
|
117
|
+
# In this case, we need to create a new thread, run a separate event loop in
|
|
118
|
+
# that thread, and use it instead of the main_event_loop.
|
|
119
|
+
# This is necessary because Jupyter Notebook has its own event loop,
|
|
120
|
+
# but it runs in the main thread. As long as a cell is running,
|
|
121
|
+
# the event loop will not execute properly
|
|
122
|
+
_run_coroutine_in_jupyter_notebook(coroutine_method=_async_push)
|
|
123
|
+
else:
|
|
124
|
+
# Running in mlrun api, we are in a separate thread from the one in which
|
|
125
|
+
# the main event loop, so we can just send the notifications to that loop
|
|
126
|
+
asyncio.run_coroutine_threadsafe(_async_push(), main_event_loop)
|
|
127
|
+
|
|
128
|
+
# then push sync notifications
|
|
129
|
+
if not mlrun.config.is_running_as_api():
|
|
130
|
+
_sync_push()
|
|
48
131
|
|
|
49
132
|
@staticmethod
|
|
50
133
|
def _should_notify(
|
|
51
|
-
run:
|
|
134
|
+
run: mlrun.model.RunObject,
|
|
135
|
+
notification: mlrun.model.Notification,
|
|
52
136
|
) -> bool:
|
|
53
|
-
when_states =
|
|
54
|
-
|
|
55
|
-
|
|
137
|
+
when_states = notification.when
|
|
138
|
+
run_state = run.state()
|
|
139
|
+
|
|
140
|
+
# if the notification isn't pending, don't push it
|
|
141
|
+
if (
|
|
142
|
+
notification.status
|
|
143
|
+
and notification.status != mlrun.common.schemas.NotificationStatus.PENDING
|
|
144
|
+
):
|
|
145
|
+
return False
|
|
56
146
|
|
|
57
147
|
# if at least one condition is met, notify
|
|
58
148
|
for when_state in when_states:
|
|
59
|
-
if
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
149
|
+
if when_state == run_state:
|
|
150
|
+
if (
|
|
151
|
+
run_state == "completed"
|
|
152
|
+
and evaluate_condition_in_separate_process(
|
|
153
|
+
notification.condition,
|
|
154
|
+
context={
|
|
155
|
+
"run": run.to_dict(),
|
|
156
|
+
"notification": notification.to_dict(),
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
) or run_state in ["error", "aborted"]:
|
|
160
|
+
return True
|
|
65
161
|
|
|
66
162
|
return False
|
|
67
163
|
|
|
68
|
-
def _load_notification(
|
|
69
|
-
|
|
164
|
+
def _load_notification(
|
|
165
|
+
self, run: mlrun.model.RunObject, notification_object: mlrun.model.Notification
|
|
166
|
+
) -> NotificationBase:
|
|
167
|
+
name = notification_object.name
|
|
70
168
|
notification_type = NotificationTypes(
|
|
71
|
-
|
|
169
|
+
notification_object.kind or NotificationTypes.console
|
|
72
170
|
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
171
|
+
notification = notification_type.get_notification()(
|
|
172
|
+
name, notification_object.params
|
|
173
|
+
)
|
|
174
|
+
if notification.is_async:
|
|
175
|
+
self._async_notifications.append((notification, run, notification_object))
|
|
77
176
|
else:
|
|
78
|
-
self.
|
|
177
|
+
self._sync_notifications.append((notification, run, notification_object))
|
|
79
178
|
|
|
80
|
-
|
|
179
|
+
logger.debug(
|
|
180
|
+
"Loaded notification", notification=name, type=notification_type.value
|
|
181
|
+
)
|
|
182
|
+
return notification
|
|
81
183
|
|
|
82
|
-
def
|
|
83
|
-
self,
|
|
184
|
+
def _prepare_notification_args(
|
|
185
|
+
self, run: mlrun.model.RunObject, notification_object: mlrun.model.Notification
|
|
84
186
|
):
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
187
|
+
custom_message = (
|
|
188
|
+
f": {notification_object.message}" if notification_object.message else ""
|
|
189
|
+
)
|
|
190
|
+
message = self.messages.get(run.state(), "") + custom_message
|
|
191
|
+
|
|
192
|
+
severity = (
|
|
193
|
+
notification_object.severity
|
|
194
|
+
or mlrun.common.schemas.NotificationSeverity.INFO
|
|
195
|
+
)
|
|
196
|
+
return message, severity, [run.to_dict()]
|
|
197
|
+
|
|
198
|
+
def _push_notification_sync(
|
|
199
|
+
self,
|
|
200
|
+
notification: NotificationBase,
|
|
201
|
+
run: mlrun.model.RunObject,
|
|
202
|
+
notification_object: mlrun.model.Notification,
|
|
203
|
+
db: mlrun.api.db.base.DBInterface,
|
|
204
|
+
):
|
|
205
|
+
message, severity, runs = self._prepare_notification_args(
|
|
206
|
+
run, notification_object
|
|
207
|
+
)
|
|
208
|
+
logger.debug(
|
|
209
|
+
"Pushing sync notification",
|
|
210
|
+
notification=_sanitize_notification(notification_object),
|
|
211
|
+
run_uid=run.metadata.uid,
|
|
212
|
+
)
|
|
213
|
+
try:
|
|
214
|
+
notification.push(message, severity, runs)
|
|
215
|
+
self._update_notification_status(
|
|
216
|
+
db,
|
|
217
|
+
run.metadata.uid,
|
|
218
|
+
run.metadata.project,
|
|
219
|
+
notification_object,
|
|
220
|
+
status=mlrun.common.schemas.NotificationStatus.SENT,
|
|
221
|
+
sent_time=datetime.datetime.now(tz=datetime.timezone.utc),
|
|
222
|
+
)
|
|
223
|
+
except Exception as exc:
|
|
224
|
+
self._update_notification_status(
|
|
225
|
+
db,
|
|
226
|
+
run.metadata.uid,
|
|
227
|
+
run.metadata.project,
|
|
228
|
+
notification_object,
|
|
229
|
+
status=mlrun.common.schemas.NotificationStatus.ERROR,
|
|
230
|
+
)
|
|
231
|
+
raise exc
|
|
232
|
+
|
|
233
|
+
async def _push_notification_async(
|
|
234
|
+
self,
|
|
235
|
+
notification: NotificationBase,
|
|
236
|
+
run: mlrun.model.RunObject,
|
|
237
|
+
notification_object: mlrun.model.Notification,
|
|
238
|
+
db: mlrun.api.db.base.DBInterface,
|
|
239
|
+
):
|
|
240
|
+
message, severity, runs = self._prepare_notification_args(
|
|
241
|
+
run, notification_object
|
|
242
|
+
)
|
|
243
|
+
logger.debug(
|
|
244
|
+
"Pushing async notification",
|
|
245
|
+
notification=_sanitize_notification(notification_object),
|
|
246
|
+
run_uid=run.metadata.uid,
|
|
247
|
+
)
|
|
248
|
+
try:
|
|
249
|
+
await notification.push(message, severity, runs)
|
|
250
|
+
|
|
251
|
+
await run_in_threadpool(
|
|
252
|
+
self._update_notification_status,
|
|
253
|
+
db,
|
|
254
|
+
run.metadata.uid,
|
|
255
|
+
run.metadata.project,
|
|
256
|
+
notification_object,
|
|
257
|
+
status=mlrun.common.schemas.NotificationStatus.SENT,
|
|
258
|
+
sent_time=datetime.datetime.now(tz=datetime.timezone.utc),
|
|
259
|
+
)
|
|
260
|
+
except Exception as exc:
|
|
261
|
+
await run_in_threadpool(
|
|
262
|
+
self._update_notification_status,
|
|
263
|
+
db,
|
|
264
|
+
run.metadata.uid,
|
|
265
|
+
run.metadata.project,
|
|
266
|
+
notification_object,
|
|
267
|
+
status=mlrun.common.schemas.NotificationStatus.ERROR,
|
|
268
|
+
)
|
|
269
|
+
raise exc
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def _update_notification_status(
|
|
273
|
+
db: mlrun.api.db.base.DBInterface,
|
|
274
|
+
run_uid: str,
|
|
275
|
+
project: str,
|
|
276
|
+
notification: mlrun.model.Notification,
|
|
277
|
+
status: str = None,
|
|
278
|
+
sent_time: typing.Optional[datetime.datetime] = None,
|
|
279
|
+
):
|
|
280
|
+
|
|
281
|
+
# nothing to update if not running as api
|
|
282
|
+
# note, the notification mechanism may run "locally" for certain runtimes
|
|
283
|
+
if not mlrun.config.is_running_as_api():
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
# TODO: move to api side
|
|
287
|
+
db_session = mlrun.api.db.session.create_session()
|
|
288
|
+
notification.status = status or notification.status
|
|
289
|
+
notification.sent_time = sent_time or notification.sent_time
|
|
290
|
+
|
|
291
|
+
# store directly in db, no need to use crud as the secrets are already loaded
|
|
292
|
+
db.store_run_notifications(
|
|
293
|
+
db_session,
|
|
294
|
+
[notification],
|
|
295
|
+
run_uid,
|
|
296
|
+
project,
|
|
297
|
+
)
|
|
88
298
|
|
|
89
299
|
|
|
90
300
|
class CustomNotificationPusher(object):
|
|
91
301
|
def __init__(self, notification_types: typing.List[str] = None):
|
|
92
|
-
|
|
302
|
+
notifications = {
|
|
93
303
|
notification_type: NotificationTypes(notification_type).get_notification()()
|
|
94
304
|
for notification_type in notification_types
|
|
95
305
|
}
|
|
306
|
+
self._sync_notifications = {
|
|
307
|
+
notification_type: notification
|
|
308
|
+
for notification_type, notification in notifications.items()
|
|
309
|
+
if not notification.is_async
|
|
310
|
+
}
|
|
311
|
+
self._async_notifications = {
|
|
312
|
+
notification_type: notification
|
|
313
|
+
for notification_type, notification in notifications.items()
|
|
314
|
+
if notification.is_async
|
|
315
|
+
}
|
|
96
316
|
|
|
97
317
|
def push(
|
|
98
318
|
self,
|
|
99
319
|
message: str,
|
|
100
|
-
severity: typing.Union[
|
|
320
|
+
severity: typing.Union[
|
|
321
|
+
mlrun.common.schemas.NotificationSeverity, str
|
|
322
|
+
] = mlrun.common.schemas.NotificationSeverity.INFO,
|
|
101
323
|
runs: typing.Union[mlrun.lists.RunList, list] = None,
|
|
102
324
|
custom_html: str = None,
|
|
103
325
|
):
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
326
|
+
def _sync_push():
|
|
327
|
+
for notification_type, notification in self._sync_notifications.items():
|
|
328
|
+
if self.should_push_notification(notification_type):
|
|
329
|
+
notification.push(message, severity, runs, custom_html)
|
|
330
|
+
|
|
331
|
+
async def _async_push():
|
|
332
|
+
tasks = []
|
|
333
|
+
for notification_type, notification in self._async_notifications.items():
|
|
334
|
+
if self.should_push_notification(notification_type):
|
|
335
|
+
tasks.append(
|
|
336
|
+
notification.push(message, severity, runs, custom_html)
|
|
337
|
+
)
|
|
338
|
+
# return exceptions to "best-effort" fire all notifications
|
|
339
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
340
|
+
|
|
341
|
+
# first push async notifications
|
|
342
|
+
main_event_loop = asyncio.get_event_loop()
|
|
343
|
+
if not main_event_loop.is_running():
|
|
344
|
+
# If running mlrun SDK locally (not from jupyter), there isn't necessarily an event loop.
|
|
345
|
+
# We create a new event loop and run the async push function in it.
|
|
346
|
+
main_event_loop.run_until_complete(_async_push())
|
|
347
|
+
elif mlrun.utils.helpers.is_running_in_jupyter_notebook():
|
|
348
|
+
# Running in Jupyter notebook.
|
|
349
|
+
# In this case, we need to create a new thread, run a separate event loop in
|
|
350
|
+
# that thread, and use it instead of the main_event_loop.
|
|
351
|
+
# This is necessary because Jupyter Notebook has its own event loop,
|
|
352
|
+
# but it runs in the main thread. As long as a cell is running,
|
|
353
|
+
# the event loop will not execute properly
|
|
354
|
+
_run_coroutine_in_jupyter_notebook(coroutine_method=_async_push)
|
|
355
|
+
else:
|
|
356
|
+
# Running in mlrun api, we are in a separate thread from the one in which
|
|
357
|
+
# the main event loop, so we can just send the notifications to that loop
|
|
358
|
+
asyncio.run_coroutine_threadsafe(_async_push(), main_event_loop)
|
|
359
|
+
|
|
360
|
+
# then push sync notifications
|
|
361
|
+
if not mlrun.config.is_running_as_api():
|
|
362
|
+
_sync_push()
|
|
107
363
|
|
|
108
364
|
def add_notification(
|
|
109
365
|
self, notification_type: str, params: typing.Dict[str, str] = None
|
|
110
366
|
):
|
|
111
|
-
if notification_type in self.
|
|
112
|
-
self.
|
|
367
|
+
if notification_type in self._async_notifications:
|
|
368
|
+
self._async_notifications[notification_type].load_notification(params)
|
|
369
|
+
elif notification_type in self._sync_notifications:
|
|
370
|
+
self._sync_notifications[notification_type].load_notification(params)
|
|
113
371
|
else:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
372
|
+
notification = NotificationTypes(notification_type).get_notification()(
|
|
373
|
+
params=params,
|
|
374
|
+
)
|
|
375
|
+
if notification.is_async:
|
|
376
|
+
self._async_notifications[notification_type] = notification
|
|
377
|
+
else:
|
|
378
|
+
self._sync_notifications[notification_type] = notification
|
|
117
379
|
|
|
118
|
-
def
|
|
119
|
-
|
|
380
|
+
def remove_notification(self, notification_type: str):
|
|
381
|
+
if notification_type in self._async_notifications:
|
|
382
|
+
del self._async_notifications[notification_type]
|
|
383
|
+
|
|
384
|
+
elif notification_type in self._sync_notifications:
|
|
385
|
+
del self._sync_notifications[notification_type]
|
|
386
|
+
|
|
387
|
+
else:
|
|
388
|
+
logger.warning(f"No notification of type {notification_type} in project")
|
|
389
|
+
|
|
390
|
+
def edit_notification(
|
|
391
|
+
self, notification_type: str, params: typing.Dict[str, str] = None
|
|
392
|
+
):
|
|
393
|
+
self.remove_notification(notification_type)
|
|
394
|
+
self.add_notification(notification_type, params)
|
|
395
|
+
|
|
396
|
+
def should_push_notification(self, notification_type):
|
|
397
|
+
notifications = {}
|
|
398
|
+
notifications.update(self._sync_notifications)
|
|
399
|
+
notifications.update(self._async_notifications)
|
|
400
|
+
notification = notifications.get(notification_type)
|
|
120
401
|
if not notification or not notification.active:
|
|
121
402
|
return False
|
|
122
403
|
|
|
123
|
-
# get notification's inverse dependencies, and only
|
|
404
|
+
# get notification's inverse dependencies, and only push the notification if
|
|
124
405
|
# none of its inverse dependencies are being sent
|
|
125
406
|
inverse_dependencies = NotificationTypes(
|
|
126
407
|
notification_type
|
|
127
408
|
).inverse_dependencies()
|
|
128
409
|
for inverse_dependency in inverse_dependencies:
|
|
129
|
-
inverse_dependency_notification =
|
|
130
|
-
inverse_dependency
|
|
131
|
-
)
|
|
410
|
+
inverse_dependency_notification = notifications.get(inverse_dependency)
|
|
132
411
|
if (
|
|
133
412
|
inverse_dependency_notification
|
|
134
413
|
and inverse_dependency_notification.active
|
|
@@ -144,7 +423,7 @@ class CustomNotificationPusher(object):
|
|
|
144
423
|
pipeline_id: str = None,
|
|
145
424
|
has_workflow_url: bool = False,
|
|
146
425
|
):
|
|
147
|
-
message = f"
|
|
426
|
+
message = f"Workflow started in project {project}"
|
|
148
427
|
if pipeline_id:
|
|
149
428
|
message += f" id={pipeline_id}"
|
|
150
429
|
commit_id = (
|
|
@@ -194,3 +473,45 @@ class CustomNotificationPusher(object):
|
|
|
194
473
|
if state:
|
|
195
474
|
text += f", state={state}"
|
|
196
475
|
self.push(text, "info", runs=runs_list)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def _sanitize_notification(notification: mlrun.model.Notification):
|
|
479
|
+
notification_dict = notification.to_dict()
|
|
480
|
+
notification_dict.pop("params", None)
|
|
481
|
+
return notification_dict
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def _separate_sync_notifications(
|
|
485
|
+
notifications: typing.List[NotificationBase],
|
|
486
|
+
) -> typing.Tuple[typing.List[NotificationBase], typing.List[NotificationBase]]:
|
|
487
|
+
sync_notifications = []
|
|
488
|
+
async_notifications = []
|
|
489
|
+
for notification in notifications:
|
|
490
|
+
if notification.is_async:
|
|
491
|
+
async_notifications.append(notification)
|
|
492
|
+
else:
|
|
493
|
+
sync_notifications.append(notification)
|
|
494
|
+
return sync_notifications, async_notifications
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _run_coroutine_in_jupyter_notebook(coroutine_method):
|
|
498
|
+
"""
|
|
499
|
+
Execute a coroutine in a Jupyter Notebook environment.
|
|
500
|
+
|
|
501
|
+
This function creates a new thread pool executor with a single thread and a new event loop.
|
|
502
|
+
It sets the created event loop as the current event loop.
|
|
503
|
+
Then, it submits the coroutine to the event loop and waits for its completion.
|
|
504
|
+
|
|
505
|
+
This approach is used in Jupyter Notebook to ensure the proper execution of the event loop in a separate thread,
|
|
506
|
+
allowing for the asynchronous push operation to be executed while the notebook is running.
|
|
507
|
+
|
|
508
|
+
:param coroutine_method: The coroutine method to be executed.
|
|
509
|
+
:return: The result of the executed coroutine.
|
|
510
|
+
"""
|
|
511
|
+
thread_pool_executer = ThreadPoolExecutor(1)
|
|
512
|
+
async_event_loop = asyncio.new_event_loop()
|
|
513
|
+
thread_pool_executer.submit(asyncio.set_event_loop, async_event_loop).result()
|
|
514
|
+
result = thread_pool_executer.submit(
|
|
515
|
+
async_event_loop.run_until_complete, coroutine_method()
|
|
516
|
+
).result()
|
|
517
|
+
return result
|
mlrun/utils/regex.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2023 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.
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
|
|
16
|
+
# pipeline param format which is passed when running a pipeline (e.g. {{pipelineparam:op=;name=mem}})
|
|
17
|
+
# https://github.com/kubeflow/pipelines/blob/16edebf4eaf84cd7478e2601ef4878ab339a7854/sdk/python/kfp/dsl/_pipeline_param.py#L213
|
|
18
|
+
# this is expected to be resolved at runtime
|
|
19
|
+
pipeline_param = [r"{{pipelineparam:op=([\w\s_-]*);name=([\w\s_-]+)}}"]
|
|
20
|
+
|
|
16
21
|
# k8s character limit is for 63 characters
|
|
17
22
|
k8s_character_limit = [r"^.{0,63}$"]
|
|
18
23
|
|
mlrun/utils/singleton.py
CHANGED
mlrun/utils/v3io_clients.py
CHANGED