mlrun 1.3.3__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.

Files changed (444) hide show
  1. mlrun/__init__.py +3 -3
  2. mlrun/__main__.py +79 -37
  3. mlrun/api/__init__.py +1 -1
  4. mlrun/api/api/__init__.py +1 -1
  5. mlrun/api/api/api.py +4 -4
  6. mlrun/api/api/deps.py +10 -21
  7. mlrun/api/api/endpoints/__init__.py +1 -1
  8. mlrun/api/api/endpoints/artifacts.py +64 -36
  9. mlrun/api/api/endpoints/auth.py +4 -4
  10. mlrun/api/api/endpoints/background_tasks.py +11 -11
  11. mlrun/api/api/endpoints/client_spec.py +5 -5
  12. mlrun/api/api/endpoints/clusterization_spec.py +6 -4
  13. mlrun/api/api/endpoints/feature_store.py +124 -115
  14. mlrun/api/api/endpoints/files.py +22 -14
  15. mlrun/api/api/endpoints/frontend_spec.py +28 -21
  16. mlrun/api/api/endpoints/functions.py +142 -87
  17. mlrun/api/api/endpoints/grafana_proxy.py +89 -442
  18. mlrun/api/api/endpoints/healthz.py +20 -7
  19. mlrun/api/api/endpoints/hub.py +320 -0
  20. mlrun/api/api/endpoints/internal/__init__.py +1 -1
  21. mlrun/api/api/endpoints/internal/config.py +1 -1
  22. mlrun/api/api/endpoints/internal/memory_reports.py +9 -9
  23. mlrun/api/api/endpoints/logs.py +11 -11
  24. mlrun/api/api/endpoints/model_endpoints.py +74 -70
  25. mlrun/api/api/endpoints/operations.py +13 -9
  26. mlrun/api/api/endpoints/pipelines.py +93 -88
  27. mlrun/api/api/endpoints/projects.py +35 -35
  28. mlrun/api/api/endpoints/runs.py +69 -27
  29. mlrun/api/api/endpoints/runtime_resources.py +28 -28
  30. mlrun/api/api/endpoints/schedules.py +98 -41
  31. mlrun/api/api/endpoints/secrets.py +37 -32
  32. mlrun/api/api/endpoints/submit.py +12 -12
  33. mlrun/api/api/endpoints/tags.py +20 -22
  34. mlrun/api/api/utils.py +251 -42
  35. mlrun/api/constants.py +1 -1
  36. mlrun/api/crud/__init__.py +18 -15
  37. mlrun/api/crud/artifacts.py +10 -10
  38. mlrun/api/crud/client_spec.py +4 -4
  39. mlrun/api/crud/clusterization_spec.py +3 -3
  40. mlrun/api/crud/feature_store.py +54 -46
  41. mlrun/api/crud/functions.py +3 -3
  42. mlrun/api/crud/hub.py +312 -0
  43. mlrun/api/crud/logs.py +11 -9
  44. mlrun/api/crud/model_monitoring/__init__.py +3 -3
  45. mlrun/api/crud/model_monitoring/grafana.py +435 -0
  46. mlrun/api/crud/model_monitoring/model_endpoints.py +352 -129
  47. mlrun/api/crud/notifications.py +149 -0
  48. mlrun/api/crud/pipelines.py +67 -52
  49. mlrun/api/crud/projects.py +51 -23
  50. mlrun/api/crud/runs.py +7 -5
  51. mlrun/api/crud/runtime_resources.py +13 -13
  52. mlrun/api/{db/filedb → crud/runtimes}/__init__.py +1 -1
  53. mlrun/api/crud/runtimes/nuclio/__init__.py +14 -0
  54. mlrun/api/crud/runtimes/nuclio/function.py +505 -0
  55. mlrun/api/crud/runtimes/nuclio/helpers.py +310 -0
  56. mlrun/api/crud/secrets.py +88 -46
  57. mlrun/api/crud/tags.py +5 -5
  58. mlrun/api/db/__init__.py +1 -1
  59. mlrun/api/db/base.py +102 -54
  60. mlrun/api/db/init_db.py +2 -3
  61. mlrun/api/db/session.py +4 -12
  62. mlrun/api/db/sqldb/__init__.py +1 -1
  63. mlrun/api/db/sqldb/db.py +439 -196
  64. mlrun/api/db/sqldb/helpers.py +1 -1
  65. mlrun/api/db/sqldb/models/__init__.py +3 -3
  66. mlrun/api/db/sqldb/models/models_mysql.py +82 -64
  67. mlrun/api/db/sqldb/models/models_sqlite.py +76 -64
  68. mlrun/api/db/sqldb/session.py +27 -20
  69. mlrun/api/initial_data.py +82 -24
  70. mlrun/api/launcher.py +196 -0
  71. mlrun/api/main.py +91 -22
  72. mlrun/api/middlewares.py +6 -5
  73. mlrun/api/migrations_mysql/env.py +1 -1
  74. mlrun/api/migrations_mysql/versions/28383af526f3_market_place_to_hub.py +40 -0
  75. mlrun/api/migrations_mysql/versions/32bae1b0e29c_increase_timestamp_fields_precision.py +1 -1
  76. mlrun/api/migrations_mysql/versions/4903aef6a91d_tag_foreign_key_and_cascades.py +1 -1
  77. mlrun/api/migrations_mysql/versions/5f1351c88a19_adding_background_tasks_table.py +1 -1
  78. mlrun/api/migrations_mysql/versions/88e656800d6a_add_requested_logs_column_and_index_to_.py +1 -1
  79. mlrun/api/migrations_mysql/versions/9d16de5f03a7_adding_data_versions_table.py +1 -1
  80. mlrun/api/migrations_mysql/versions/b86f5b53f3d7_adding_name_and_updated_to_runs_table.py +1 -1
  81. mlrun/api/migrations_mysql/versions/c4af40b0bf61_init.py +1 -1
  82. mlrun/api/migrations_mysql/versions/c905d15bd91d_notifications.py +72 -0
  83. mlrun/api/migrations_mysql/versions/ee041e8fdaa0_adding_next_run_time_column_to_schedule_.py +1 -1
  84. mlrun/api/migrations_sqlite/env.py +1 -1
  85. mlrun/api/migrations_sqlite/versions/11f8dd2dc9fe_init.py +1 -1
  86. mlrun/api/migrations_sqlite/versions/1c954f8cb32d_schedule_last_run_uri.py +1 -1
  87. mlrun/api/migrations_sqlite/versions/2b6d23c715aa_adding_feature_sets.py +1 -1
  88. mlrun/api/migrations_sqlite/versions/4acd9430b093_market_place_to_hub.py +77 -0
  89. mlrun/api/migrations_sqlite/versions/6401142f2d7c_adding_next_run_time_column_to_schedule_.py +1 -1
  90. mlrun/api/migrations_sqlite/versions/64d90a1a69bc_adding_background_tasks_table.py +1 -1
  91. mlrun/api/migrations_sqlite/versions/803438ecd005_add_requested_logs_column_to_runs.py +1 -1
  92. mlrun/api/migrations_sqlite/versions/863114f0c659_refactoring_feature_set.py +1 -1
  93. mlrun/api/migrations_sqlite/versions/959ae00528ad_notifications.py +63 -0
  94. mlrun/api/migrations_sqlite/versions/accf9fc83d38_adding_data_versions_table.py +1 -1
  95. mlrun/api/migrations_sqlite/versions/b68e8e897a28_schedule_labels.py +1 -1
  96. mlrun/api/migrations_sqlite/versions/bcd0c1f9720c_adding_project_labels.py +1 -1
  97. mlrun/api/migrations_sqlite/versions/cf21882f938e_schedule_id.py +1 -1
  98. mlrun/api/migrations_sqlite/versions/d781f58f607f_tag_object_name_string.py +1 -1
  99. mlrun/api/migrations_sqlite/versions/deac06871ace_adding_marketplace_sources_table.py +1 -1
  100. mlrun/api/migrations_sqlite/versions/e1dd5983c06b_schedule_concurrency_limit.py +1 -1
  101. mlrun/api/migrations_sqlite/versions/e5594ed3ab53_adding_name_and_updated_to_runs_table.py +1 -1
  102. mlrun/api/migrations_sqlite/versions/f4249b4ba6fa_adding_feature_vectors.py +1 -1
  103. mlrun/api/migrations_sqlite/versions/f7b5a1a03629_adding_feature_labels.py +1 -1
  104. mlrun/api/schemas/__init__.py +216 -138
  105. mlrun/api/utils/__init__.py +1 -1
  106. mlrun/api/utils/asyncio.py +1 -1
  107. mlrun/api/utils/auth/__init__.py +1 -1
  108. mlrun/api/utils/auth/providers/__init__.py +1 -1
  109. mlrun/api/utils/auth/providers/base.py +7 -7
  110. mlrun/api/utils/auth/providers/nop.py +6 -7
  111. mlrun/api/utils/auth/providers/opa.py +17 -17
  112. mlrun/api/utils/auth/verifier.py +36 -34
  113. mlrun/api/utils/background_tasks.py +24 -24
  114. mlrun/{builder.py → api/utils/builder.py} +216 -123
  115. mlrun/api/utils/clients/__init__.py +1 -1
  116. mlrun/api/utils/clients/chief.py +19 -4
  117. mlrun/api/utils/clients/iguazio.py +106 -60
  118. mlrun/api/utils/clients/log_collector.py +1 -1
  119. mlrun/api/utils/clients/nuclio.py +23 -23
  120. mlrun/api/utils/clients/protocols/grpc.py +2 -2
  121. mlrun/api/utils/db/__init__.py +1 -1
  122. mlrun/api/utils/db/alembic.py +1 -1
  123. mlrun/api/utils/db/backup.py +1 -1
  124. mlrun/api/utils/db/mysql.py +24 -25
  125. mlrun/api/utils/db/sql_collation.py +1 -1
  126. mlrun/api/utils/db/sqlite_migration.py +2 -2
  127. mlrun/api/utils/events/__init__.py +14 -0
  128. mlrun/api/utils/events/base.py +57 -0
  129. mlrun/api/utils/events/events_factory.py +41 -0
  130. mlrun/api/utils/events/iguazio.py +217 -0
  131. mlrun/api/utils/events/nop.py +55 -0
  132. mlrun/api/utils/helpers.py +16 -13
  133. mlrun/api/utils/memory_reports.py +1 -1
  134. mlrun/api/utils/periodic.py +6 -3
  135. mlrun/api/utils/projects/__init__.py +1 -1
  136. mlrun/api/utils/projects/follower.py +33 -33
  137. mlrun/api/utils/projects/leader.py +36 -34
  138. mlrun/api/utils/projects/member.py +27 -27
  139. mlrun/api/utils/projects/remotes/__init__.py +1 -1
  140. mlrun/api/utils/projects/remotes/follower.py +13 -13
  141. mlrun/api/utils/projects/remotes/leader.py +10 -10
  142. mlrun/api/utils/projects/remotes/nop_follower.py +27 -21
  143. mlrun/api/utils/projects/remotes/nop_leader.py +17 -16
  144. mlrun/api/utils/scheduler.py +140 -51
  145. mlrun/api/utils/singletons/__init__.py +1 -1
  146. mlrun/api/utils/singletons/db.py +9 -15
  147. mlrun/api/utils/singletons/k8s.py +677 -5
  148. mlrun/api/utils/singletons/logs_dir.py +1 -1
  149. mlrun/api/utils/singletons/project_member.py +1 -1
  150. mlrun/api/utils/singletons/scheduler.py +1 -1
  151. mlrun/artifacts/__init__.py +2 -2
  152. mlrun/artifacts/base.py +8 -2
  153. mlrun/artifacts/dataset.py +5 -3
  154. mlrun/artifacts/manager.py +7 -1
  155. mlrun/artifacts/model.py +15 -4
  156. mlrun/artifacts/plots.py +1 -1
  157. mlrun/common/__init__.py +1 -1
  158. mlrun/common/constants.py +15 -0
  159. mlrun/common/model_monitoring.py +209 -0
  160. mlrun/common/schemas/__init__.py +167 -0
  161. mlrun/{api → common}/schemas/artifact.py +13 -14
  162. mlrun/{api → common}/schemas/auth.py +10 -8
  163. mlrun/{api → common}/schemas/background_task.py +3 -3
  164. mlrun/{api → common}/schemas/client_spec.py +1 -1
  165. mlrun/{api → common}/schemas/clusterization_spec.py +3 -3
  166. mlrun/{api → common}/schemas/constants.py +21 -8
  167. mlrun/common/schemas/events.py +36 -0
  168. mlrun/{api → common}/schemas/feature_store.py +2 -1
  169. mlrun/{api → common}/schemas/frontend_spec.py +7 -6
  170. mlrun/{api → common}/schemas/function.py +5 -5
  171. mlrun/{api → common}/schemas/http.py +3 -3
  172. mlrun/common/schemas/hub.py +134 -0
  173. mlrun/{api → common}/schemas/k8s.py +3 -3
  174. mlrun/{api → common}/schemas/memory_reports.py +1 -1
  175. mlrun/common/schemas/model_endpoints.py +342 -0
  176. mlrun/common/schemas/notification.py +57 -0
  177. mlrun/{api → common}/schemas/object.py +6 -6
  178. mlrun/{api → common}/schemas/pipeline.py +3 -3
  179. mlrun/{api → common}/schemas/project.py +6 -5
  180. mlrun/common/schemas/regex.py +24 -0
  181. mlrun/common/schemas/runs.py +30 -0
  182. mlrun/{api → common}/schemas/runtime_resource.py +3 -3
  183. mlrun/{api → common}/schemas/schedule.py +19 -7
  184. mlrun/{api → common}/schemas/secret.py +3 -3
  185. mlrun/{api → common}/schemas/tag.py +2 -2
  186. mlrun/common/types.py +25 -0
  187. mlrun/config.py +152 -20
  188. mlrun/data_types/__init__.py +7 -2
  189. mlrun/data_types/data_types.py +4 -2
  190. mlrun/data_types/infer.py +1 -1
  191. mlrun/data_types/spark.py +10 -3
  192. mlrun/datastore/__init__.py +10 -3
  193. mlrun/datastore/azure_blob.py +1 -1
  194. mlrun/datastore/base.py +185 -53
  195. mlrun/datastore/datastore.py +1 -1
  196. mlrun/datastore/filestore.py +1 -1
  197. mlrun/datastore/google_cloud_storage.py +1 -1
  198. mlrun/datastore/inmem.py +4 -1
  199. mlrun/datastore/redis.py +1 -1
  200. mlrun/datastore/s3.py +1 -1
  201. mlrun/datastore/sources.py +192 -70
  202. mlrun/datastore/spark_udf.py +44 -0
  203. mlrun/datastore/store_resources.py +4 -4
  204. mlrun/datastore/targets.py +115 -45
  205. mlrun/datastore/utils.py +127 -5
  206. mlrun/datastore/v3io.py +1 -1
  207. mlrun/datastore/wasbfs/__init__.py +1 -1
  208. mlrun/datastore/wasbfs/fs.py +1 -1
  209. mlrun/db/__init__.py +7 -5
  210. mlrun/db/base.py +112 -68
  211. mlrun/db/httpdb.py +445 -277
  212. mlrun/db/nopdb.py +491 -0
  213. mlrun/db/sqldb.py +112 -65
  214. mlrun/errors.py +6 -1
  215. mlrun/execution.py +44 -22
  216. mlrun/feature_store/__init__.py +1 -1
  217. mlrun/feature_store/api.py +143 -95
  218. mlrun/feature_store/common.py +16 -20
  219. mlrun/feature_store/feature_set.py +42 -12
  220. mlrun/feature_store/feature_vector.py +32 -21
  221. mlrun/feature_store/ingestion.py +9 -12
  222. mlrun/feature_store/retrieval/__init__.py +3 -2
  223. mlrun/feature_store/retrieval/base.py +388 -66
  224. mlrun/feature_store/retrieval/dask_merger.py +63 -151
  225. mlrun/feature_store/retrieval/job.py +30 -12
  226. mlrun/feature_store/retrieval/local_merger.py +40 -133
  227. mlrun/feature_store/retrieval/spark_merger.py +129 -127
  228. mlrun/feature_store/retrieval/storey_merger.py +173 -0
  229. mlrun/feature_store/steps.py +132 -15
  230. mlrun/features.py +8 -3
  231. mlrun/frameworks/__init__.py +1 -1
  232. mlrun/frameworks/_common/__init__.py +1 -1
  233. mlrun/frameworks/_common/artifacts_library.py +1 -1
  234. mlrun/frameworks/_common/mlrun_interface.py +1 -1
  235. mlrun/frameworks/_common/model_handler.py +1 -1
  236. mlrun/frameworks/_common/plan.py +1 -1
  237. mlrun/frameworks/_common/producer.py +1 -1
  238. mlrun/frameworks/_common/utils.py +1 -1
  239. mlrun/frameworks/_dl_common/__init__.py +1 -1
  240. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -1
  241. mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
  242. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +1 -1
  243. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +1 -1
  244. mlrun/frameworks/_dl_common/model_handler.py +1 -1
  245. mlrun/frameworks/_dl_common/utils.py +1 -1
  246. mlrun/frameworks/_ml_common/__init__.py +1 -1
  247. mlrun/frameworks/_ml_common/artifacts_library.py +1 -1
  248. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -1
  249. mlrun/frameworks/_ml_common/loggers/logger.py +1 -1
  250. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
  251. mlrun/frameworks/_ml_common/model_handler.py +1 -1
  252. mlrun/frameworks/_ml_common/pkl_model_server.py +13 -1
  253. mlrun/frameworks/_ml_common/plan.py +1 -1
  254. mlrun/frameworks/_ml_common/plans/__init__.py +1 -1
  255. mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +1 -6
  256. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +1 -1
  257. mlrun/frameworks/_ml_common/plans/dataset_plan.py +1 -1
  258. mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +1 -1
  259. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +1 -1
  260. mlrun/frameworks/_ml_common/producer.py +1 -1
  261. mlrun/frameworks/_ml_common/utils.py +1 -1
  262. mlrun/frameworks/auto_mlrun/__init__.py +1 -1
  263. mlrun/frameworks/auto_mlrun/auto_mlrun.py +1 -1
  264. mlrun/frameworks/huggingface/__init__.py +1 -1
  265. mlrun/frameworks/huggingface/model_server.py +1 -1
  266. mlrun/frameworks/lgbm/__init__.py +1 -1
  267. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -1
  268. mlrun/frameworks/lgbm/callbacks/callback.py +1 -1
  269. mlrun/frameworks/lgbm/callbacks/logging_callback.py +1 -1
  270. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +1 -1
  271. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -1
  272. mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -1
  273. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +1 -1
  274. mlrun/frameworks/lgbm/mlrun_interfaces/model_mlrun_interface.py +1 -1
  275. mlrun/frameworks/lgbm/model_handler.py +1 -1
  276. mlrun/frameworks/lgbm/model_server.py +1 -1
  277. mlrun/frameworks/lgbm/utils.py +1 -1
  278. mlrun/frameworks/onnx/__init__.py +1 -1
  279. mlrun/frameworks/onnx/dataset.py +1 -1
  280. mlrun/frameworks/onnx/mlrun_interface.py +1 -1
  281. mlrun/frameworks/onnx/model_handler.py +1 -1
  282. mlrun/frameworks/onnx/model_server.py +1 -1
  283. mlrun/frameworks/parallel_coordinates.py +1 -1
  284. mlrun/frameworks/pytorch/__init__.py +1 -1
  285. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -1
  286. mlrun/frameworks/pytorch/callbacks/callback.py +1 -1
  287. mlrun/frameworks/pytorch/callbacks/logging_callback.py +1 -1
  288. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +1 -1
  289. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +1 -1
  290. mlrun/frameworks/pytorch/callbacks_handler.py +1 -1
  291. mlrun/frameworks/pytorch/mlrun_interface.py +1 -1
  292. mlrun/frameworks/pytorch/model_handler.py +1 -1
  293. mlrun/frameworks/pytorch/model_server.py +1 -1
  294. mlrun/frameworks/pytorch/utils.py +1 -1
  295. mlrun/frameworks/sklearn/__init__.py +1 -1
  296. mlrun/frameworks/sklearn/estimator.py +1 -1
  297. mlrun/frameworks/sklearn/metric.py +1 -1
  298. mlrun/frameworks/sklearn/metrics_library.py +1 -1
  299. mlrun/frameworks/sklearn/mlrun_interface.py +1 -1
  300. mlrun/frameworks/sklearn/model_handler.py +1 -1
  301. mlrun/frameworks/sklearn/utils.py +1 -1
  302. mlrun/frameworks/tf_keras/__init__.py +1 -1
  303. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -1
  304. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  305. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +1 -1
  306. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +1 -1
  307. mlrun/frameworks/tf_keras/mlrun_interface.py +1 -1
  308. mlrun/frameworks/tf_keras/model_handler.py +1 -1
  309. mlrun/frameworks/tf_keras/model_server.py +1 -1
  310. mlrun/frameworks/tf_keras/utils.py +1 -1
  311. mlrun/frameworks/xgboost/__init__.py +1 -1
  312. mlrun/frameworks/xgboost/mlrun_interface.py +1 -1
  313. mlrun/frameworks/xgboost/model_handler.py +1 -1
  314. mlrun/frameworks/xgboost/utils.py +1 -1
  315. mlrun/k8s_utils.py +14 -765
  316. mlrun/kfpops.py +14 -17
  317. mlrun/launcher/__init__.py +13 -0
  318. mlrun/launcher/base.py +406 -0
  319. mlrun/launcher/client.py +159 -0
  320. mlrun/launcher/factory.py +50 -0
  321. mlrun/launcher/local.py +276 -0
  322. mlrun/launcher/remote.py +178 -0
  323. mlrun/lists.py +10 -2
  324. mlrun/mlutils/__init__.py +1 -1
  325. mlrun/mlutils/data.py +1 -1
  326. mlrun/mlutils/models.py +1 -1
  327. mlrun/mlutils/plots.py +1 -1
  328. mlrun/model.py +252 -14
  329. mlrun/model_monitoring/__init__.py +41 -0
  330. mlrun/model_monitoring/features_drift_table.py +1 -1
  331. mlrun/model_monitoring/helpers.py +123 -38
  332. mlrun/model_monitoring/model_endpoint.py +144 -0
  333. mlrun/model_monitoring/model_monitoring_batch.py +310 -259
  334. mlrun/model_monitoring/stores/__init__.py +106 -0
  335. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +448 -0
  336. mlrun/model_monitoring/stores/model_endpoint_store.py +147 -0
  337. mlrun/model_monitoring/stores/models/__init__.py +23 -0
  338. mlrun/model_monitoring/stores/models/base.py +18 -0
  339. mlrun/model_monitoring/stores/models/mysql.py +100 -0
  340. mlrun/model_monitoring/stores/models/sqlite.py +98 -0
  341. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +370 -0
  342. mlrun/model_monitoring/stream_processing_fs.py +239 -271
  343. mlrun/package/__init__.py +163 -0
  344. mlrun/package/context_handler.py +325 -0
  345. mlrun/package/errors.py +47 -0
  346. mlrun/package/packager.py +298 -0
  347. mlrun/{runtimes/package → package/packagers}/__init__.py +3 -1
  348. mlrun/package/packagers/default_packager.py +422 -0
  349. mlrun/package/packagers/numpy_packagers.py +612 -0
  350. mlrun/package/packagers/pandas_packagers.py +968 -0
  351. mlrun/package/packagers/python_standard_library_packagers.py +616 -0
  352. mlrun/package/packagers_manager.py +786 -0
  353. mlrun/package/utils/__init__.py +53 -0
  354. mlrun/package/utils/_archiver.py +226 -0
  355. mlrun/package/utils/_formatter.py +211 -0
  356. mlrun/package/utils/_pickler.py +234 -0
  357. mlrun/package/utils/_supported_format.py +71 -0
  358. mlrun/package/utils/log_hint_utils.py +93 -0
  359. mlrun/package/utils/type_hint_utils.py +298 -0
  360. mlrun/platforms/__init__.py +1 -1
  361. mlrun/platforms/iguazio.py +34 -2
  362. mlrun/platforms/other.py +1 -1
  363. mlrun/projects/__init__.py +1 -1
  364. mlrun/projects/operations.py +14 -9
  365. mlrun/projects/pipelines.py +31 -13
  366. mlrun/projects/project.py +762 -238
  367. mlrun/render.py +49 -19
  368. mlrun/run.py +57 -326
  369. mlrun/runtimes/__init__.py +3 -9
  370. mlrun/runtimes/base.py +247 -784
  371. mlrun/runtimes/constants.py +1 -1
  372. mlrun/runtimes/daskjob.py +45 -41
  373. mlrun/runtimes/funcdoc.py +43 -7
  374. mlrun/runtimes/function.py +66 -656
  375. mlrun/runtimes/function_reference.py +1 -1
  376. mlrun/runtimes/generators.py +1 -1
  377. mlrun/runtimes/kubejob.py +99 -116
  378. mlrun/runtimes/local.py +59 -66
  379. mlrun/runtimes/mpijob/__init__.py +1 -1
  380. mlrun/runtimes/mpijob/abstract.py +13 -15
  381. mlrun/runtimes/mpijob/v1.py +3 -1
  382. mlrun/runtimes/mpijob/v1alpha1.py +1 -1
  383. mlrun/runtimes/nuclio.py +1 -1
  384. mlrun/runtimes/pod.py +51 -26
  385. mlrun/runtimes/remotesparkjob.py +3 -1
  386. mlrun/runtimes/serving.py +12 -4
  387. mlrun/runtimes/sparkjob/__init__.py +1 -2
  388. mlrun/runtimes/sparkjob/abstract.py +44 -31
  389. mlrun/runtimes/sparkjob/spark3job.py +11 -9
  390. mlrun/runtimes/utils.py +61 -42
  391. mlrun/secrets.py +16 -18
  392. mlrun/serving/__init__.py +3 -2
  393. mlrun/serving/merger.py +1 -1
  394. mlrun/serving/remote.py +1 -1
  395. mlrun/serving/routers.py +39 -42
  396. mlrun/serving/server.py +23 -13
  397. mlrun/serving/serving_wrapper.py +1 -1
  398. mlrun/serving/states.py +172 -39
  399. mlrun/serving/utils.py +1 -1
  400. mlrun/serving/v1_serving.py +1 -1
  401. mlrun/serving/v2_serving.py +29 -21
  402. mlrun/utils/__init__.py +1 -2
  403. mlrun/utils/async_http.py +8 -1
  404. mlrun/utils/azure_vault.py +1 -1
  405. mlrun/utils/clones.py +2 -2
  406. mlrun/utils/condition_evaluator.py +65 -0
  407. mlrun/utils/db.py +52 -0
  408. mlrun/utils/helpers.py +188 -13
  409. mlrun/utils/http.py +89 -54
  410. mlrun/utils/logger.py +48 -8
  411. mlrun/utils/model_monitoring.py +132 -100
  412. mlrun/utils/notifications/__init__.py +1 -1
  413. mlrun/utils/notifications/notification/__init__.py +8 -6
  414. mlrun/utils/notifications/notification/base.py +20 -14
  415. mlrun/utils/notifications/notification/console.py +7 -4
  416. mlrun/utils/notifications/notification/git.py +36 -19
  417. mlrun/utils/notifications/notification/ipython.py +10 -8
  418. mlrun/utils/notifications/notification/slack.py +18 -13
  419. mlrun/utils/notifications/notification_pusher.py +377 -56
  420. mlrun/utils/regex.py +6 -1
  421. mlrun/utils/singleton.py +1 -1
  422. mlrun/utils/v3io_clients.py +1 -1
  423. mlrun/utils/vault.py +270 -269
  424. mlrun/utils/version/__init__.py +1 -1
  425. mlrun/utils/version/version.json +2 -2
  426. mlrun/utils/version/version.py +1 -1
  427. {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/METADATA +16 -10
  428. mlrun-1.4.0.dist-info/RECORD +434 -0
  429. mlrun/api/api/endpoints/marketplace.py +0 -257
  430. mlrun/api/crud/marketplace.py +0 -221
  431. mlrun/api/crud/model_monitoring/model_endpoint_store.py +0 -847
  432. mlrun/api/db/filedb/db.py +0 -518
  433. mlrun/api/schemas/marketplace.py +0 -128
  434. mlrun/api/schemas/model_endpoints.py +0 -185
  435. mlrun/db/filedb.py +0 -891
  436. mlrun/feature_store/retrieval/online.py +0 -92
  437. mlrun/model_monitoring/constants.py +0 -67
  438. mlrun/runtimes/package/context_handler.py +0 -711
  439. mlrun/runtimes/sparkjob/spark2job.py +0 -59
  440. mlrun-1.3.3.dist-info/RECORD +0 -381
  441. {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/LICENSE +0 -0
  442. {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/WHEEL +0 -0
  443. {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/entry_points.txt +0 -0
  444. {mlrun-1.3.3.dist-info → mlrun-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Iguazio
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 ast
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, NotificationSeverity, NotificationTypes
33
+ from .notification import NotificationBase, NotificationTypes
24
34
 
25
35
 
26
36
  class NotificationPusher(object):
27
37
 
28
38
  messages = {
29
- "success": "Run completed",
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._notification_data = []
36
- self._notifications = {}
46
+ self._sync_notifications = []
47
+ self._async_notifications = []
37
48
 
38
49
  for run in self._runs:
39
- for notification_config in run.get("spec", {}).get("notifications", []):
40
- if self._should_notify(run, notification_config):
41
- self._notification_data.append((run, notification_config))
42
-
43
- def push(self):
44
- for notification_data in self._notification_data:
45
- self._send_notification(
46
- self._load_notification(notification_data[1]), *notification_data
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: typing.Union[mlrun.model.RunObject, dict], notification_config: dict
134
+ run: mlrun.model.RunObject,
135
+ notification: mlrun.model.Notification,
52
136
  ) -> bool:
53
- when_states = notification_config.get("when", [])
54
- condition = notification_config.get("condition", "")
55
- run_state = run.get("status", {}).get("state", "")
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
- when_state == "success"
61
- and run_state == "success"
62
- and (not condition or ast.literal_eval(condition))
63
- ) or (when_state == "failure" and run_state == "error"):
64
- return True
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(self, notification_config: dict) -> NotificationBase:
69
- params = notification_config.get("params", {})
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
- notification_config.get("type", "console")
169
+ notification_object.kind or NotificationTypes.console
72
170
  )
73
- if notification_type not in self._notifications:
74
- self._notifications[
75
- notification_type
76
- ] = notification_type.get_notification()(params)
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._notifications[notification_type].load_notification(params)
177
+ self._sync_notifications.append((notification, run, notification_object))
79
178
 
80
- return self._notifications[notification_type]
179
+ logger.debug(
180
+ "Loaded notification", notification=name, type=notification_type.value
181
+ )
182
+ return notification
81
183
 
82
- def _send_notification(
83
- self, notification: NotificationBase, run: dict, notification_config: dict
184
+ def _prepare_notification_args(
185
+ self, run: mlrun.model.RunObject, notification_object: mlrun.model.Notification
84
186
  ):
85
- message = self.messages.get(run.get("status", {}).get("state", ""), "")
86
- severity = notification_config.get("severity", NotificationSeverity.INFO)
87
- notification.send(message, severity, [run])
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
- self._notifications = {
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[NotificationSeverity, str] = NotificationSeverity.INFO,
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
- for notification_type, notification in self._notifications.items():
105
- if self.should_send_notification(notification_type):
106
- notification.send(message, severity, runs, custom_html)
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._notifications:
112
- self._notifications[notification_type].load_notification(params)
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
- self._notifications[notification_type] = NotificationTypes(
115
- notification_type
116
- ).get_notification()(params)
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 should_send_notification(self, notification_type):
119
- notification = self._notifications.get(notification_type)
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 send the notification if
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 = self._notifications.get(
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"Pipeline started in project {project}"
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 2018 Iguazio
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
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Iguazio
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.
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Iguazio
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.