mage-ai 0.9.70__py3-none-any.whl → 0.9.71__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 mage-ai might be problematic. Click here for more details.

Files changed (568) hide show
  1. mage_ai/ai/utils/xgboost.py +222 -0
  2. mage_ai/api/errors.py +37 -25
  3. mage_ai/api/operations/base.py +13 -1
  4. mage_ai/api/parsers/PipelineScheduleParser.py +1 -1
  5. mage_ai/api/policies/BlockOutputPolicy.py +40 -17
  6. mage_ai/api/policies/GlobalDataProductPolicy.py +91 -41
  7. mage_ai/api/policies/KernelPolicy.py +55 -32
  8. mage_ai/api/policies/KernelProcessPolicy.py +56 -0
  9. mage_ai/api/policies/OutputPolicy.py +73 -41
  10. mage_ai/api/policies/PipelinePolicy.py +206 -138
  11. mage_ai/api/presenters/BlockLayoutItemPresenter.py +9 -7
  12. mage_ai/api/presenters/BlockPresenter.py +1 -1
  13. mage_ai/api/presenters/GlobalDataProductPresenter.py +6 -1
  14. mage_ai/api/presenters/KernelPresenter.py +5 -26
  15. mage_ai/api/presenters/KernelProcessPresenter.py +28 -0
  16. mage_ai/api/presenters/PipelinePresenter.py +18 -5
  17. mage_ai/api/presenters/StatusPresenter.py +2 -0
  18. mage_ai/api/presenters/SyncPresenter.py +25 -0
  19. mage_ai/api/resources/AutocompleteItemResource.py +1 -1
  20. mage_ai/api/resources/BlockLayoutItemResource.py +90 -44
  21. mage_ai/api/resources/BlockOutputResource.py +42 -9
  22. mage_ai/api/resources/BlockResource.py +4 -3
  23. mage_ai/api/resources/BlockRunResource.py +27 -22
  24. mage_ai/api/resources/ClusterResource.py +4 -1
  25. mage_ai/api/resources/CustomTemplateResource.py +34 -14
  26. mage_ai/api/resources/DataProviderResource.py +1 -1
  27. mage_ai/api/resources/ExecutionStateResource.py +3 -1
  28. mage_ai/api/resources/FileContentResource.py +8 -2
  29. mage_ai/api/resources/FileResource.py +10 -4
  30. mage_ai/api/resources/FileVersionResource.py +3 -1
  31. mage_ai/api/resources/GitBranchResource.py +46 -9
  32. mage_ai/api/resources/GlobalDataProductResource.py +44 -7
  33. mage_ai/api/resources/GlobalHookResource.py +4 -1
  34. mage_ai/api/resources/IntegrationDestinationResource.py +6 -2
  35. mage_ai/api/resources/IntegrationSourceResource.py +8 -4
  36. mage_ai/api/resources/IntegrationSourceStreamResource.py +6 -2
  37. mage_ai/api/resources/KernelProcessResource.py +44 -0
  38. mage_ai/api/resources/KernelResource.py +25 -3
  39. mage_ai/api/resources/OutputResource.py +33 -11
  40. mage_ai/api/resources/PageBlockLayoutResource.py +34 -23
  41. mage_ai/api/resources/PipelineInteractionResource.py +31 -15
  42. mage_ai/api/resources/PipelineResource.py +250 -123
  43. mage_ai/api/resources/PipelineRunResource.py +11 -3
  44. mage_ai/api/resources/PipelineScheduleResource.py +7 -2
  45. mage_ai/api/resources/PipelineTriggerResource.py +6 -1
  46. mage_ai/api/resources/ProjectResource.py +18 -7
  47. mage_ai/api/resources/SecretResource.py +1 -1
  48. mage_ai/api/resources/SeedResource.py +8 -1
  49. mage_ai/api/resources/StatusResource.py +21 -6
  50. mage_ai/api/resources/SyncResource.py +6 -8
  51. mage_ai/api/resources/VariableResource.py +46 -26
  52. mage_ai/api/resources/VersionControlProjectResource.py +9 -2
  53. mage_ai/api/resources/WidgetResource.py +1 -1
  54. mage_ai/api/resources/WorkspaceResource.py +1 -1
  55. mage_ai/api/views.py +47 -40
  56. mage_ai/authentication/permissions/seed.py +16 -2
  57. mage_ai/authentication/providers/oidc.py +21 -1
  58. mage_ai/autocomplete/utils.py +13 -9
  59. mage_ai/cache/base.py +1 -1
  60. mage_ai/cache/block.py +18 -12
  61. mage_ai/cache/block_action_object/__init__.py +32 -4
  62. mage_ai/cache/file.py +22 -19
  63. mage_ai/cache/pipeline.py +18 -12
  64. mage_ai/cli/main.py +1 -0
  65. mage_ai/cluster_manager/aws/emr_cluster_manager.py +9 -5
  66. mage_ai/cluster_manager/config.py +2 -2
  67. mage_ai/cluster_manager/manage.py +1 -1
  68. mage_ai/cluster_manager/workspace/base.py +1 -1
  69. mage_ai/command_center/applications/factory.py +10 -7
  70. mage_ai/command_center/files/factory.py +17 -15
  71. mage_ai/command_center/utils.py +25 -13
  72. mage_ai/data/__init__.py +0 -0
  73. mage_ai/data/constants.py +45 -0
  74. mage_ai/data/models/__init__.py +0 -0
  75. mage_ai/data/models/base.py +119 -0
  76. mage_ai/data/models/constants.py +1 -0
  77. mage_ai/data/models/generator.py +115 -0
  78. mage_ai/data/models/manager.py +168 -0
  79. mage_ai/data/models/pyarrow/__init__.py +0 -0
  80. mage_ai/data/models/pyarrow/record_batch.py +55 -0
  81. mage_ai/data/models/pyarrow/shared.py +21 -0
  82. mage_ai/data/models/pyarrow/table.py +8 -0
  83. mage_ai/data/models/reader.py +103 -0
  84. mage_ai/data/models/utils.py +59 -0
  85. mage_ai/data/models/writer.py +91 -0
  86. mage_ai/data/tabular/__init__.py +0 -0
  87. mage_ai/data/tabular/constants.py +23 -0
  88. mage_ai/data/tabular/mocks.py +19 -0
  89. mage_ai/data/tabular/models.py +126 -0
  90. mage_ai/data/tabular/reader.py +602 -0
  91. mage_ai/data/tabular/utils.py +102 -0
  92. mage_ai/data/tabular/writer.py +266 -0
  93. mage_ai/data/variables/__init__.py +0 -0
  94. mage_ai/data/variables/wrapper.py +54 -0
  95. mage_ai/data_cleaner/analysis/charts.py +61 -39
  96. mage_ai/data_cleaner/column_types/column_type_detector.py +53 -31
  97. mage_ai/data_cleaner/estimators/encoders.py +5 -2
  98. mage_ai/data_integrations/utils/scheduler.py +16 -11
  99. mage_ai/data_preparation/decorators.py +1 -0
  100. mage_ai/data_preparation/executors/block_executor.py +237 -155
  101. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +1 -1
  102. mage_ai/data_preparation/git/__init__.py +27 -7
  103. mage_ai/data_preparation/git/api.py +7 -1
  104. mage_ai/data_preparation/git/utils.py +22 -16
  105. mage_ai/data_preparation/logging/logger_manager.py +4 -3
  106. mage_ai/data_preparation/models/block/__init__.py +1542 -878
  107. mage_ai/data_preparation/models/block/data_integration/mixins.py +4 -3
  108. mage_ai/data_preparation/models/block/dynamic/__init__.py +17 -6
  109. mage_ai/data_preparation/models/block/dynamic/child.py +41 -102
  110. mage_ai/data_preparation/models/block/dynamic/constants.py +1 -0
  111. mage_ai/data_preparation/models/block/dynamic/counter.py +296 -0
  112. mage_ai/data_preparation/models/block/dynamic/data.py +16 -0
  113. mage_ai/data_preparation/models/block/dynamic/factory.py +163 -0
  114. mage_ai/data_preparation/models/block/dynamic/models.py +19 -0
  115. mage_ai/data_preparation/models/block/dynamic/shared.py +92 -0
  116. mage_ai/data_preparation/models/block/dynamic/utils.py +291 -168
  117. mage_ai/data_preparation/models/block/dynamic/variables.py +384 -144
  118. mage_ai/data_preparation/models/block/dynamic/wrappers.py +77 -0
  119. mage_ai/data_preparation/models/block/extension/utils.py +10 -1
  120. mage_ai/data_preparation/models/block/global_data_product/__init__.py +10 -1
  121. mage_ai/data_preparation/models/block/integration/__init__.py +6 -2
  122. mage_ai/data_preparation/models/block/outputs.py +722 -0
  123. mage_ai/data_preparation/models/block/platform/mixins.py +7 -8
  124. mage_ai/data_preparation/models/block/r/__init__.py +56 -38
  125. mage_ai/data_preparation/models/block/settings/__init__.py +0 -0
  126. mage_ai/data_preparation/models/block/settings/dynamic/__init__.py +0 -0
  127. mage_ai/data_preparation/models/block/settings/dynamic/constants.py +7 -0
  128. mage_ai/data_preparation/models/block/settings/dynamic/mixins.py +118 -0
  129. mage_ai/data_preparation/models/block/settings/dynamic/models.py +31 -0
  130. mage_ai/data_preparation/models/block/settings/global_data_products/__init__.py +0 -0
  131. mage_ai/data_preparation/models/block/settings/global_data_products/mixins.py +20 -0
  132. mage_ai/data_preparation/models/block/settings/global_data_products/models.py +46 -0
  133. mage_ai/data_preparation/models/block/settings/variables/__init__.py +0 -0
  134. mage_ai/data_preparation/models/block/settings/variables/mixins.py +74 -0
  135. mage_ai/data_preparation/models/block/settings/variables/models.py +49 -0
  136. mage_ai/data_preparation/models/block/spark/mixins.py +2 -1
  137. mage_ai/data_preparation/models/block/sql/__init__.py +30 -5
  138. mage_ai/data_preparation/models/block/sql/utils/shared.py +21 -3
  139. mage_ai/data_preparation/models/block/utils.py +127 -70
  140. mage_ai/data_preparation/models/constants.py +19 -14
  141. mage_ai/data_preparation/models/custom_templates/custom_block_template.py +18 -13
  142. mage_ai/data_preparation/models/custom_templates/custom_pipeline_template.py +33 -16
  143. mage_ai/data_preparation/models/custom_templates/utils.py +1 -1
  144. mage_ai/data_preparation/models/file.py +41 -28
  145. mage_ai/data_preparation/models/global_data_product/__init__.py +88 -58
  146. mage_ai/data_preparation/models/global_hooks/models.py +1 -0
  147. mage_ai/data_preparation/models/interfaces.py +29 -0
  148. mage_ai/data_preparation/models/pipeline.py +365 -180
  149. mage_ai/data_preparation/models/pipelines/integration_pipeline.py +1 -2
  150. mage_ai/data_preparation/models/pipelines/seed.py +1 -1
  151. mage_ai/data_preparation/models/project/__init__.py +66 -18
  152. mage_ai/data_preparation/models/project/constants.py +2 -0
  153. mage_ai/data_preparation/models/triggers/__init__.py +120 -24
  154. mage_ai/data_preparation/models/utils.py +467 -17
  155. mage_ai/data_preparation/models/variable.py +1028 -137
  156. mage_ai/data_preparation/models/variables/__init__.py +0 -0
  157. mage_ai/data_preparation/models/variables/cache.py +149 -0
  158. mage_ai/data_preparation/models/variables/constants.py +72 -0
  159. mage_ai/data_preparation/models/variables/summarizer.py +336 -0
  160. mage_ai/data_preparation/models/variables/utils.py +77 -0
  161. mage_ai/data_preparation/models/widget/__init__.py +63 -41
  162. mage_ai/data_preparation/models/widget/charts.py +40 -27
  163. mage_ai/data_preparation/models/widget/constants.py +2 -0
  164. mage_ai/data_preparation/models/widget/utils.py +3 -3
  165. mage_ai/data_preparation/preferences.py +3 -3
  166. mage_ai/data_preparation/repo_manager.py +55 -21
  167. mage_ai/data_preparation/storage/base_storage.py +2 -2
  168. mage_ai/data_preparation/storage/gcs_storage.py +7 -4
  169. mage_ai/data_preparation/storage/local_storage.py +6 -3
  170. mage_ai/data_preparation/storage/s3_storage.py +5 -2
  171. mage_ai/data_preparation/templates/data_exporters/streaming/oracledb.yaml +8 -0
  172. mage_ai/data_preparation/variable_manager.py +281 -76
  173. mage_ai/io/base.py +3 -2
  174. mage_ai/io/bigquery.py +1 -0
  175. mage_ai/io/redshift.py +7 -5
  176. mage_ai/kernels/__init__.py +0 -0
  177. mage_ai/kernels/models.py +188 -0
  178. mage_ai/kernels/utils.py +169 -0
  179. mage_ai/orchestration/concurrency.py +6 -2
  180. mage_ai/orchestration/db/__init__.py +1 -0
  181. mage_ai/orchestration/db/migrations/versions/0227396a216c_add_userproject_table.py +38 -0
  182. mage_ai/orchestration/db/models/dynamic/__init__.py +0 -0
  183. mage_ai/orchestration/db/models/dynamic/controller.py +67 -0
  184. mage_ai/orchestration/db/models/oauth.py +2 -9
  185. mage_ai/orchestration/db/models/projects.py +10 -0
  186. mage_ai/orchestration/db/models/schedules.py +204 -187
  187. mage_ai/orchestration/db/models/schedules_project_platform.py +18 -12
  188. mage_ai/orchestration/db/models/utils.py +46 -5
  189. mage_ai/orchestration/metrics/pipeline_run.py +8 -9
  190. mage_ai/orchestration/notification/sender.py +1 -0
  191. mage_ai/orchestration/pipeline_scheduler_original.py +32 -8
  192. mage_ai/orchestration/pipeline_scheduler_project_platform.py +1 -1
  193. mage_ai/orchestration/run_status_checker.py +11 -4
  194. mage_ai/orchestration/triggers/api.py +12 -1
  195. mage_ai/presenters/charts/data_sources/base.py +4 -2
  196. mage_ai/presenters/charts/data_sources/block.py +15 -9
  197. mage_ai/presenters/charts/data_sources/chart_code.py +8 -5
  198. mage_ai/presenters/charts/data_sources/constants.py +1 -0
  199. mage_ai/presenters/charts/data_sources/system_metrics.py +22 -0
  200. mage_ai/presenters/interactions/models.py +11 -7
  201. mage_ai/presenters/pages/loaders/pipelines.py +5 -3
  202. mage_ai/presenters/pages/models/page_components/pipeline_schedules.py +3 -1
  203. mage_ai/presenters/utils.py +2 -0
  204. mage_ai/server/api/blocks.py +2 -1
  205. mage_ai/server/api/downloads.py +5 -1
  206. mage_ai/server/api/triggers.py +3 -1
  207. mage_ai/server/constants.py +1 -1
  208. mage_ai/server/frontend_dist/404.html +5 -5
  209. mage_ai/server/frontend_dist/_next/static/UZLabyPgcxtZvp0O0EUUS/_buildManifest.js +1 -0
  210. mage_ai/server/frontend_dist/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
  211. mage_ai/server/frontend_dist/_next/static/chunks/{1557-b3502f3f1aa92ac7.js → 1557-25a7d985d5564fd3.js} +1 -1
  212. mage_ai/server/frontend_dist/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
  213. mage_ai/server/frontend_dist/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
  214. mage_ai/server/frontend_dist/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
  215. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3763-61b542dafdbf5754.js → frontend_dist/_next/static/chunks/3763-40780c6d1e4b261d.js} +1 -1
  216. mage_ai/server/frontend_dist/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
  217. mage_ai/server/frontend_dist/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
  218. mage_ai/server/frontend_dist/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
  219. mage_ai/server/frontend_dist/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
  220. mage_ai/server/frontend_dist/_next/static/chunks/5699-176f445e1313f001.js +1 -0
  221. mage_ai/server/frontend_dist/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
  222. mage_ai/server/frontend_dist/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
  223. mage_ai/server/frontend_dist/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
  224. mage_ai/server/frontend_dist/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
  225. mage_ai/server/frontend_dist/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
  226. mage_ai/server/frontend_dist/_next/static/chunks/{main-77fe248a6fbd12d8.js → main-b99d4e30a88d9dc7.js} +1 -1
  227. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-9fe2d9d07c94e968.js +1 -0
  228. mage_ai/server/frontend_dist/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
  229. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
  230. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
  231. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/overview-597b74828bf105db.js → frontend_dist/_next/static/chunks/pages/overview-9f1ac4ec003884f3.js} +1 -1
  232. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-7181b086c93784d2.js → [...slug]-7e737f6fc7e83e9b.js} +1 -1
  233. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
  234. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
  235. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
  236. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
  237. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-7acc7afc00df17c2.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-5f4c8128b2413fd8.js} +1 -1
  238. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
  239. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
  240. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
  241. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js → frontend_dist/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js} +1 -1
  242. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js → frontend_dist/_next/static/chunks/pages/settings/platform/settings-319ddbabc239e91b.js} +1 -1
  243. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
  244. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
  245. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
  246. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
  247. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
  248. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
  249. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
  250. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
  251. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
  252. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-d079359c241db804.js → webpack-ac7fdc472bedf682.js} +1 -1
  253. mage_ai/server/frontend_dist/block-layout.html +3 -3
  254. mage_ai/server/frontend_dist/compute.html +6 -6
  255. mage_ai/server/frontend_dist/files.html +6 -6
  256. mage_ai/server/frontend_dist/global-data-products/[...slug].html +6 -6
  257. mage_ai/server/frontend_dist/global-data-products.html +6 -6
  258. mage_ai/server/frontend_dist/global-hooks/[...slug].html +6 -6
  259. mage_ai/server/frontend_dist/global-hooks.html +6 -6
  260. mage_ai/server/frontend_dist/index.html +3 -3
  261. mage_ai/server/frontend_dist/manage/files.html +6 -6
  262. mage_ai/server/frontend_dist/manage/settings.html +6 -6
  263. mage_ai/server/frontend_dist/manage/users/[user].html +6 -6
  264. mage_ai/server/frontend_dist/manage/users/new.html +6 -6
  265. mage_ai/server/frontend_dist/manage/users.html +6 -6
  266. mage_ai/server/frontend_dist/manage.html +6 -6
  267. mage_ai/server/frontend_dist/oauth.html +5 -5
  268. mage_ai/server/frontend_dist/overview.html +6 -6
  269. mage_ai/server/frontend_dist/pipeline-runs.html +6 -6
  270. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  271. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +6 -6
  272. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +6 -6
  273. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +3 -3
  274. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +6 -6
  275. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  276. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  277. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +6 -6
  278. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +6 -6
  279. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +6 -6
  280. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +6 -6
  281. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +6 -6
  282. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  283. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +6 -6
  284. mage_ai/server/frontend_dist/pipelines/[pipeline].html +3 -3
  285. mage_ai/server/frontend_dist/pipelines.html +6 -6
  286. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +6 -6
  287. mage_ai/server/frontend_dist/platform/global-hooks.html +6 -6
  288. mage_ai/server/frontend_dist/settings/account/profile.html +6 -6
  289. mage_ai/server/frontend_dist/settings/platform/preferences.html +6 -6
  290. mage_ai/server/frontend_dist/settings/platform/settings.html +6 -6
  291. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +6 -6
  292. mage_ai/server/frontend_dist/settings/workspace/permissions.html +6 -6
  293. mage_ai/server/frontend_dist/settings/workspace/preferences.html +6 -6
  294. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +6 -6
  295. mage_ai/server/frontend_dist/settings/workspace/roles.html +6 -6
  296. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +6 -6
  297. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +6 -6
  298. mage_ai/server/frontend_dist/settings/workspace/users.html +6 -6
  299. mage_ai/server/frontend_dist/settings.html +3 -3
  300. mage_ai/server/frontend_dist/sign-in.html +12 -12
  301. mage_ai/server/frontend_dist/templates/[...slug].html +6 -6
  302. mage_ai/server/frontend_dist/templates.html +6 -6
  303. mage_ai/server/frontend_dist/terminal.html +6 -6
  304. mage_ai/server/frontend_dist/test.html +3 -3
  305. mage_ai/server/frontend_dist/triggers.html +6 -6
  306. mage_ai/server/frontend_dist/version-control.html +6 -6
  307. mage_ai/server/frontend_dist_base_path_template/404.html +5 -5
  308. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
  309. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1557-b3502f3f1aa92ac7.js → 1557-25a7d985d5564fd3.js} +1 -1
  310. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
  311. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
  312. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
  313. mage_ai/server/{frontend_dist/_next/static/chunks/3763-61b542dafdbf5754.js → frontend_dist_base_path_template/_next/static/chunks/3763-40780c6d1e4b261d.js} +1 -1
  314. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
  315. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
  316. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
  317. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
  318. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-176f445e1313f001.js +1 -0
  319. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
  320. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
  321. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
  322. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
  323. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
  324. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{main-70b78159c2bb3fe1.js → main-384298e9133cec76.js} +1 -1
  325. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-13a578bce3b7f30c.js +1 -0
  326. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
  327. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
  328. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
  329. mage_ai/server/{frontend_dist/_next/static/chunks/pages/overview-597b74828bf105db.js → frontend_dist_base_path_template/_next/static/chunks/pages/overview-9f1ac4ec003884f3.js} +1 -1
  330. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-7181b086c93784d2.js → [...slug]-7e737f6fc7e83e9b.js} +1 -1
  331. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
  332. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
  333. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
  334. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
  335. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-7acc7afc00df17c2.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-5f4c8128b2413fd8.js} +1 -1
  336. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
  337. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
  338. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
  339. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js} +1 -1
  340. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-319ddbabc239e91b.js} +1 -1
  341. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
  342. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
  343. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
  344. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
  345. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
  346. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
  347. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
  348. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
  349. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
  350. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-68c003fb6a175cd7.js → webpack-481689d9989710cd.js} +1 -1
  351. mage_ai/server/frontend_dist_base_path_template/_next/static/kcptwoOU-JJJg6Vwpkfmx/_buildManifest.js +1 -0
  352. mage_ai/server/frontend_dist_base_path_template/block-layout.html +3 -3
  353. mage_ai/server/frontend_dist_base_path_template/compute.html +6 -6
  354. mage_ai/server/frontend_dist_base_path_template/files.html +6 -6
  355. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +6 -6
  356. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +6 -6
  357. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +6 -6
  358. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +6 -6
  359. mage_ai/server/frontend_dist_base_path_template/index.html +3 -3
  360. mage_ai/server/frontend_dist_base_path_template/manage/files.html +6 -6
  361. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +6 -6
  362. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +6 -6
  363. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +6 -6
  364. mage_ai/server/frontend_dist_base_path_template/manage/users.html +6 -6
  365. mage_ai/server/frontend_dist_base_path_template/manage.html +6 -6
  366. mage_ai/server/frontend_dist_base_path_template/oauth.html +5 -5
  367. mage_ai/server/frontend_dist_base_path_template/overview.html +6 -6
  368. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +6 -6
  369. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  370. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +6 -6
  371. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +6 -6
  372. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +3 -3
  373. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +6 -6
  374. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  375. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  376. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +6 -6
  377. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +6 -6
  378. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +6 -6
  379. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +6 -6
  380. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +6 -6
  381. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  382. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +6 -6
  383. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +3 -3
  384. mage_ai/server/frontend_dist_base_path_template/pipelines.html +6 -6
  385. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +6 -6
  386. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +6 -6
  387. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +6 -6
  388. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +6 -6
  389. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +6 -6
  390. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +6 -6
  391. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +6 -6
  392. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +6 -6
  393. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +6 -6
  394. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +6 -6
  395. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +6 -6
  396. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +6 -6
  397. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +6 -6
  398. mage_ai/server/frontend_dist_base_path_template/settings.html +3 -3
  399. mage_ai/server/frontend_dist_base_path_template/sign-in.html +12 -12
  400. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +6 -6
  401. mage_ai/server/frontend_dist_base_path_template/templates.html +6 -6
  402. mage_ai/server/frontend_dist_base_path_template/terminal.html +6 -6
  403. mage_ai/server/frontend_dist_base_path_template/test.html +3 -3
  404. mage_ai/server/frontend_dist_base_path_template/triggers.html +6 -6
  405. mage_ai/server/frontend_dist_base_path_template/version-control.html +6 -6
  406. mage_ai/server/kernel_output_parser.py +4 -1
  407. mage_ai/server/scheduler_manager.py +9 -0
  408. mage_ai/server/server.py +35 -31
  409. mage_ai/server/utils/custom_output.py +284 -0
  410. mage_ai/server/utils/execute_custom_code.py +245 -0
  411. mage_ai/server/utils/output_display.py +123 -289
  412. mage_ai/server/websocket_server.py +116 -69
  413. mage_ai/services/k8s/config.py +23 -0
  414. mage_ai/services/k8s/job_manager.py +6 -1
  415. mage_ai/services/ssh/aws/emr/utils.py +8 -8
  416. mage_ai/settings/keys/auth.py +1 -0
  417. mage_ai/settings/platform/__init__.py +159 -38
  418. mage_ai/settings/platform/constants.py +5 -0
  419. mage_ai/settings/platform/utils.py +53 -10
  420. mage_ai/settings/repo.py +26 -12
  421. mage_ai/settings/server.py +128 -37
  422. mage_ai/shared/array.py +24 -1
  423. mage_ai/shared/complex.py +45 -0
  424. mage_ai/shared/config.py +2 -1
  425. mage_ai/shared/custom_logger.py +11 -0
  426. mage_ai/shared/dates.py +10 -6
  427. mage_ai/shared/files.py +63 -8
  428. mage_ai/shared/hash.py +33 -9
  429. mage_ai/shared/io.py +9 -5
  430. mage_ai/shared/models.py +82 -24
  431. mage_ai/shared/outputs.py +87 -0
  432. mage_ai/shared/parsers.py +141 -15
  433. mage_ai/shared/path_fixer.py +11 -7
  434. mage_ai/shared/singletons/__init__.py +0 -0
  435. mage_ai/shared/singletons/base.py +47 -0
  436. mage_ai/shared/singletons/memory.py +38 -0
  437. mage_ai/shared/strings.py +34 -1
  438. mage_ai/shared/yaml.py +24 -0
  439. mage_ai/streaming/sinks/oracledb.py +57 -0
  440. mage_ai/streaming/sinks/sink_factory.py +4 -0
  441. mage_ai/system/__init__.py +0 -0
  442. mage_ai/system/constants.py +14 -0
  443. mage_ai/system/memory/__init__.py +0 -0
  444. mage_ai/system/memory/constants.py +1 -0
  445. mage_ai/system/memory/manager.py +174 -0
  446. mage_ai/system/memory/presenters.py +158 -0
  447. mage_ai/system/memory/process.py +216 -0
  448. mage_ai/system/memory/samples.py +13 -0
  449. mage_ai/system/memory/utils.py +656 -0
  450. mage_ai/system/memory/wrappers.py +177 -0
  451. mage_ai/system/models.py +58 -0
  452. mage_ai/system/storage/__init__.py +0 -0
  453. mage_ai/system/storage/utils.py +29 -0
  454. mage_ai/tests/api/endpoints/mixins.py +2 -2
  455. mage_ai/tests/api/endpoints/test_blocks.py +2 -1
  456. mage_ai/tests/api/endpoints/test_custom_designs.py +4 -4
  457. mage_ai/tests/api/endpoints/test_pipeline_runs.py +2 -2
  458. mage_ai/tests/api/endpoints/test_projects.py +2 -1
  459. mage_ai/tests/api/operations/base/test_base.py +27 -27
  460. mage_ai/tests/api/operations/base/test_base_with_user_authentication.py +27 -27
  461. mage_ai/tests/api/operations/base/test_base_with_user_permissions.py +23 -23
  462. mage_ai/tests/api/operations/test_syncs.py +6 -4
  463. mage_ai/tests/api/resources/test_pipeline_resource.py +9 -2
  464. mage_ai/tests/authentication/providers/test_oidc.py +59 -0
  465. mage_ai/tests/base_test.py +2 -2
  466. mage_ai/tests/data/__init__.py +0 -0
  467. mage_ai/tests/data/models/__init__.py +0 -0
  468. mage_ai/tests/data_preparation/executors/test_block_executor.py +23 -16
  469. mage_ai/tests/data_preparation/git/test_git.py +4 -1
  470. mage_ai/tests/data_preparation/models/block/dynamic/test_combos.py +305 -0
  471. mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +212 -0
  472. mage_ai/tests/data_preparation/models/block/dynamic/test_factory.py +360 -0
  473. mage_ai/tests/data_preparation/models/block/dynamic/test_variables.py +332 -0
  474. mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +2 -2
  475. mage_ai/tests/data_preparation/models/block/platform/test_mixins.py +1 -1
  476. mage_ai/tests/data_preparation/models/block/sql/utils/test_shared.py +26 -1
  477. mage_ai/tests/data_preparation/models/block/test_global_data_product.py +3 -2
  478. mage_ai/tests/data_preparation/models/custom_templates/test_utils.py +5 -4
  479. mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +3 -0
  480. mage_ai/tests/data_preparation/models/global_hooks/test_predicates.py +9 -3
  481. mage_ai/tests/data_preparation/models/test_block.py +115 -120
  482. mage_ai/tests/data_preparation/models/test_blocks_helper.py +114 -0
  483. mage_ai/tests/data_preparation/models/test_global_data_product.py +41 -24
  484. mage_ai/tests/data_preparation/models/test_pipeline.py +9 -6
  485. mage_ai/tests/data_preparation/models/test_project.py +4 -1
  486. mage_ai/tests/data_preparation/models/test_utils.py +80 -0
  487. mage_ai/tests/data_preparation/models/test_variable.py +242 -69
  488. mage_ai/tests/data_preparation/models/variables/__init__.py +0 -0
  489. mage_ai/tests/data_preparation/models/variables/test_summarizer.py +481 -0
  490. mage_ai/tests/data_preparation/storage/shared/__init__.py +0 -0
  491. mage_ai/tests/data_preparation/test_repo_manager.py +6 -7
  492. mage_ai/tests/data_preparation/test_variable_manager.py +57 -48
  493. mage_ai/tests/factory.py +64 -43
  494. mage_ai/tests/orchestration/db/models/test_schedules.py +3 -3
  495. mage_ai/tests/orchestration/db/models/test_schedules_dynamic_blocks.py +279 -0
  496. mage_ai/tests/orchestration/test_pipeline_scheduler.py +1 -0
  497. mage_ai/tests/orchestration/triggers/test_global_data_product.py +3 -2
  498. mage_ai/tests/orchestration/triggers/test_utils.py +3 -2
  499. mage_ai/tests/services/k8s/test_job_manager.py +18 -0
  500. mage_ai/tests/streaming/sinks/test_oracledb.py +38 -0
  501. mage_ai/tests/test_shared.py +61 -0
  502. mage_ai/usage_statistics/logger.py +7 -2
  503. mage_ai/utils/code.py +33 -19
  504. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/METADATA +5 -2
  505. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/RECORD +513 -417
  506. mage_ai/data_preparation/models/global_data_product/constants.py +0 -6
  507. mage_ai/server/frontend_dist/_next/static/RhDiJSkcjCsh4xxX4BFBk/_buildManifest.js +0 -1
  508. mage_ai/server/frontend_dist/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
  509. mage_ai/server/frontend_dist/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
  510. mage_ai/server/frontend_dist/_next/static/chunks/4783-422429203610c318.js +0 -1
  511. mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
  512. mage_ai/server/frontend_dist/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
  513. mage_ai/server/frontend_dist/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
  514. mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
  515. mage_ai/server/frontend_dist/_next/static/chunks/7966-b9b85ba10667e654.js +0 -1
  516. mage_ai/server/frontend_dist/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
  517. mage_ai/server/frontend_dist/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
  518. mage_ai/server/frontend_dist/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
  519. mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
  520. mage_ai/server/frontend_dist/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
  521. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +0 -1
  522. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
  523. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
  524. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
  525. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +0 -1
  526. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
  527. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
  528. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
  529. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +0 -1
  530. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
  531. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +0 -1
  532. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +0 -1
  533. mage_ai/server/frontend_dist_base_path_template/_next/static/TdpLLFome13qvM0gXvpHs/_buildManifest.js +0 -1
  534. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
  535. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
  536. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4783-422429203610c318.js +0 -1
  537. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
  538. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
  539. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
  540. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
  541. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-b9b85ba10667e654.js +0 -1
  542. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
  543. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
  544. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
  545. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
  546. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
  547. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +0 -1
  548. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
  549. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
  550. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
  551. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +0 -1
  552. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
  553. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
  554. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
  555. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +0 -1
  556. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
  557. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +0 -1
  558. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +0 -1
  559. mage_ai/shared/memory.py +0 -90
  560. mage_ai/tests/data_preparation/models/block/dynamic/test_dynamic_helpers.py +0 -48
  561. /mage_ai/{tests/data_preparation/shared → ai/utils}/__init__.py +0 -0
  562. /mage_ai/server/frontend_dist/_next/static/{RhDiJSkcjCsh4xxX4BFBk → UZLabyPgcxtZvp0O0EUUS}/_ssgManifest.js +0 -0
  563. /mage_ai/server/frontend_dist_base_path_template/_next/static/{TdpLLFome13qvM0gXvpHs → kcptwoOU-JJJg6Vwpkfmx}/_ssgManifest.js +0 -0
  564. /mage_ai/tests/data_preparation/{shared → storage/shared}/test_secrets.py +0 -0
  565. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/LICENSE +0 -0
  566. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/WHEEL +0 -0
  567. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/entry_points.txt +0 -0
  568. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/top_level.txt +0 -0
@@ -11,12 +11,13 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
11
11
 
12
12
  import aiofiles
13
13
  import pytz
14
- import yaml
15
14
  from jinja2 import Template
16
15
 
17
16
  from mage_ai.authentication.permissions.constants import EntityName
18
17
  from mage_ai.cache.block import BlockCache
19
18
  from mage_ai.cache.pipeline import PipelineCache
19
+ from mage_ai.data.constants import InputDataType
20
+ from mage_ai.data.tabular.models import BatchSettings
20
21
  from mage_ai.data_preparation.models.block import Block, run_blocks, run_blocks_sync
21
22
  from mage_ai.data_preparation.models.block.block_factory import BlockFactory
22
23
  from mage_ai.data_preparation.models.block.data_integration.utils import (
@@ -27,6 +28,10 @@ from mage_ai.data_preparation.models.block.dynamic.utils import (
27
28
  is_dynamic_block_child,
28
29
  )
29
30
  from mage_ai.data_preparation.models.block.errors import HasDownstreamDependencies
31
+ from mage_ai.data_preparation.models.block.extension.utils import compare_extension
32
+ from mage_ai.data_preparation.models.block.settings.variables.models import (
33
+ ChunkKeyTypeUnion,
34
+ )
30
35
  from mage_ai.data_preparation.models.constants import (
31
36
  DATA_INTEGRATION_CATALOG_FILE,
32
37
  PIPELINE_CONFIG_FILE,
@@ -47,7 +52,10 @@ from mage_ai.data_preparation.models.file import File
47
52
  from mage_ai.data_preparation.models.pipelines.models import PipelineSettings
48
53
  from mage_ai.data_preparation.models.project import Project
49
54
  from mage_ai.data_preparation.models.project.constants import FeatureUUID
50
- from mage_ai.data_preparation.models.utils import is_yaml_serializable
55
+ from mage_ai.data_preparation.models.utils import (
56
+ is_yaml_serializable,
57
+ warn_for_repo_path,
58
+ )
51
59
  from mage_ai.data_preparation.models.variable import Variable
52
60
  from mage_ai.data_preparation.repo_manager import (
53
61
  RepoConfig,
@@ -73,6 +81,7 @@ from mage_ai.shared.io import safe_write, safe_write_async
73
81
  from mage_ai.shared.path_fixer import remove_base_repo_path
74
82
  from mage_ai.shared.strings import format_enum
75
83
  from mage_ai.shared.utils import clean_name
84
+ from mage_ai.shared.yaml import load_yaml, yaml
76
85
 
77
86
  CYCLE_DETECTION_ERR_MESSAGE = 'A cycle was detected in this pipeline'
78
87
 
@@ -81,10 +90,11 @@ class Pipeline:
81
90
  def __init__(
82
91
  self,
83
92
  uuid,
84
- repo_path=None,
93
+ repo_path: str = None,
85
94
  config=None,
86
95
  repo_config=None,
87
96
  catalog=None,
97
+ context_data: Dict = None,
88
98
  use_repo_path: bool = False,
89
99
  description: str = None,
90
100
  tags: List[str] = None,
@@ -103,6 +113,14 @@ class Pipeline:
103
113
  self.extensions = {}
104
114
  self.name = None
105
115
  self.notification_config = dict()
116
+
117
+ # For multi project
118
+ warn_for_repo_path(repo_path)
119
+ self.context_data = context_data
120
+ if self.context_data is None:
121
+ self.context_data = dict()
122
+ self._project = None
123
+
106
124
  self.repo_path = repo_path or get_repo_path()
107
125
  self.retry_config = {}
108
126
  self.run_pipeline_in_one_process = False
@@ -130,17 +148,28 @@ class Pipeline:
130
148
  # Used for showing the operation history. For example: recently viewed pipelines.
131
149
  self.history = []
132
150
 
151
+ # Path of the pipeline metadata.yaml file
152
+ self._config_path = None
133
153
  if config is None:
134
154
  self.load_config_from_yaml()
135
155
  else:
136
156
  self.load_config(config, catalog=catalog)
137
157
 
138
- @classmethod
139
- def build_config_path(self, uuid: str, repo_path: str, use_repo_path: bool = False) -> str:
158
+ def build_config_path(
159
+ self,
160
+ uuid: str,
161
+ repo_path: str,
162
+ context_data: Dict = None,
163
+ use_repo_path: bool = False,
164
+ ) -> str:
140
165
  if project_platform_activated() and not use_repo_path:
141
166
  from mage_ai.settings.platform.utils import get_pipeline_config_path
142
167
 
143
- config_path, _repo_path = get_pipeline_config_path(uuid)
168
+ config_path, _repo_path = get_pipeline_config_path(
169
+ uuid,
170
+ context_data=context_data,
171
+ repo_path=repo_path,
172
+ )
144
173
  if config_path:
145
174
  return config_path
146
175
 
@@ -153,14 +182,25 @@ class Pipeline:
153
182
 
154
183
  @property
155
184
  def config_path(self):
156
- return self.build_config_path(self.uuid, self.repo_path, use_repo_path=self.use_repo_path)
185
+ if not self._config_path:
186
+ self._config_path = self.build_config_path(
187
+ self.uuid,
188
+ self.repo_path,
189
+ context_data=self.context_data,
190
+ use_repo_path=self.use_repo_path,
191
+ )
192
+ return self._config_path
157
193
 
158
194
  @property
159
195
  def catalog_config_path(self):
160
196
  if project_platform_activated() and not self.use_repo_path:
161
197
  from mage_ai.settings.platform.utils import get_pipeline_config_path
162
198
 
163
- config_path, _repo_path = get_pipeline_config_path(self.uuid)
199
+ config_path, _repo_path = get_pipeline_config_path(
200
+ self.uuid,
201
+ context_data=self.context_data,
202
+ repo_path=self.repo_path,
203
+ )
164
204
  if config_path:
165
205
  return os.path.join(os.path.dirname(config_path), DATA_INTEGRATION_CATALOG_FILE)
166
206
 
@@ -198,6 +238,16 @@ class Pipeline:
198
238
  self.uuid,
199
239
  )
200
240
 
241
+ @property
242
+ def project(self):
243
+ if self._project is not None:
244
+ return self._project
245
+
246
+ from mage_ai.data_preparation.models.project import Project
247
+
248
+ self._project = Project(context_data=self.context_data, repo_config=self.repo_config)
249
+ return self._project
250
+
201
251
  @property
202
252
  def remote_variables_dir(self):
203
253
  remote_variables_dir = self.repo_config.remote_variables_dir
@@ -216,18 +266,20 @@ class Pipeline:
216
266
 
217
267
  @property
218
268
  def all_block_configs(self) -> List[Dict]:
219
- return self.block_configs + \
220
- self.conditional_configs + \
221
- self.callback_configs + \
222
- self.widget_configs
269
+ return (
270
+ self.block_configs
271
+ + self.conditional_configs
272
+ + self.callback_configs
273
+ + self.widget_configs
274
+ )
223
275
 
224
276
  @classmethod
225
277
  def create(
226
278
  self,
227
279
  name: str,
280
+ repo_path: str = None,
228
281
  description: str = None,
229
282
  pipeline_type: PipelineType = PipelineType.PYTHON,
230
- repo_path: str = None,
231
283
  tags: List[str] = None,
232
284
  ):
233
285
  """
@@ -235,6 +287,8 @@ class Pipeline:
235
287
  2. Create a new yaml file to store pipeline config
236
288
  3. Create other files: requirements.txt, __init__.py
237
289
  """
290
+ warn_for_repo_path(repo_path)
291
+
238
292
  uuid = clean_name(name)
239
293
  pipeline_path = os.path.join(repo_path, PIPELINES_FOLDER, uuid)
240
294
  if os.path.exists(pipeline_path):
@@ -243,14 +297,17 @@ class Pipeline:
243
297
  copy_template_directory('pipeline', pipeline_path)
244
298
  # Update metadata.yaml with pipeline config
245
299
  with open(os.path.join(pipeline_path, PIPELINE_CONFIG_FILE), 'w') as fp:
246
- yaml.dump(dict(
247
- created_at=str(datetime.now(tz=pytz.UTC)),
248
- description=description,
249
- name=name,
250
- tags=tags or [],
251
- uuid=uuid,
252
- type=format_enum(pipeline_type or PipelineType.PYTHON),
253
- ), fp)
300
+ yaml.dump(
301
+ dict(
302
+ created_at=str(datetime.now(tz=pytz.UTC)),
303
+ description=description,
304
+ name=name,
305
+ tags=tags or [],
306
+ uuid=uuid,
307
+ type=format_enum(pipeline_type or PipelineType.PYTHON),
308
+ ),
309
+ fp,
310
+ )
254
311
 
255
312
  pipeline = Pipeline(
256
313
  uuid,
@@ -269,10 +326,13 @@ class Pipeline:
269
326
  zip_size = sum(e.file_size for e in zipf.infolist()) # calc zip size in bytes
270
327
  if zip_size / 1000 > PIPELINE_MAX_FILE_SIZE: # prevention against zip-bombs
271
328
  raise PipelineZipTooLargeError(
272
- f'Pipeline zip exceeds size limit {PIPELINE_MAX_FILE_SIZE/1000}Kb')
329
+ f'Pipeline zip exceeds size limit {PIPELINE_MAX_FILE_SIZE / 1000}Kb'
330
+ )
273
331
 
274
332
  # Ignore `__MACOSX` for zips created on macOS systems
275
- zip_contents = [path for path in zipf.namelist() if not path.startswith('__MACOSX')]
333
+ zip_contents = [
334
+ path for path in zipf.namelist() if not path.startswith('__MACOSX')
335
+ ]
276
336
  # Verify if zip contents are part of a root folder
277
337
  prefix = os.path.commonpath(zip_contents)
278
338
 
@@ -302,7 +362,9 @@ class Pipeline:
302
362
  raise FileWriteError(f'Failed to write pipeline file to {destination}.')
303
363
 
304
364
  # return the pipeline configuration file
305
- config_destination_path = pipeline_files[0][1] # First item is the pipeline config path
365
+ config_destination_path = pipeline_files[0][
366
+ 1
367
+ ] # First item is the pipeline config path
306
368
  ret_file = File.from_path(config_destination_path)
307
369
  ret_file.filename = new_pipeline_uuid
308
370
 
@@ -332,8 +394,10 @@ class Pipeline:
332
394
  repo_path=source_pipeline.repo_path,
333
395
  )
334
396
 
335
- if source_pipeline.type == PipelineType.INTEGRATION and \
336
- source_pipeline.data_integration is not None:
397
+ if (
398
+ source_pipeline.type == PipelineType.INTEGRATION
399
+ and source_pipeline.data_integration is not None
400
+ ):
337
401
  with open(duplicate_pipeline.catalog_config_path, 'w') as fp:
338
402
  json.dump(source_pipeline.data_integration, fp)
339
403
 
@@ -358,7 +422,7 @@ class Pipeline:
358
422
 
359
423
  block_cache = await BlockCache.initialize_cache()
360
424
  for block in blocks:
361
- block_cache.add_pipeline(block, duplicate_pipeline)
425
+ block_cache.add_pipeline(block, duplicate_pipeline, duplicate_pipeline.repo_path)
362
426
 
363
427
  return cls.get(
364
428
  duplicate_pipeline_uuid,
@@ -377,30 +441,46 @@ class Pipeline:
377
441
 
378
442
  @classmethod
379
443
  def get(
380
- self,
444
+ cls,
381
445
  uuid,
382
446
  repo_path: str = None,
447
+ repo_config=None,
383
448
  check_if_exists: bool = False,
384
449
  all_projects: bool = False,
450
+ context_data: Dict = None,
385
451
  use_repo_path: bool = False,
386
452
  ):
387
- from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
388
- IntegrationPipeline,
389
- )
453
+ warn_for_repo_path(repo_path)
390
454
 
391
- config_path, repo_path = self._get_config_path(
455
+ config_path, repo_path = cls._get_config_path(
392
456
  uuid,
393
457
  repo_path=repo_path,
394
458
  all_projects=all_projects,
459
+ context_data=context_data,
395
460
  use_repo_path=use_repo_path,
396
461
  )
397
462
 
398
- if check_if_exists and not os.path.exists(config_path):
463
+ if check_if_exists and (not config_path or not os.path.exists(config_path)):
399
464
  return None
400
465
 
401
- pipeline = self(uuid, repo_path=repo_path, use_repo_path=use_repo_path)
466
+ pipeline = cls(
467
+ uuid,
468
+ repo_path=repo_path,
469
+ repo_config=repo_config,
470
+ context_data=context_data,
471
+ use_repo_path=use_repo_path,
472
+ )
402
473
  if PipelineType.INTEGRATION == pipeline.type:
403
- pipeline = IntegrationPipeline(uuid, repo_path=repo_path)
474
+ from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
475
+ IntegrationPipeline,
476
+ )
477
+
478
+ pipeline = IntegrationPipeline(
479
+ uuid,
480
+ repo_path=repo_path,
481
+ repo_config=repo_config,
482
+ context_data=context_data,
483
+ )
404
484
 
405
485
  return pipeline
406
486
 
@@ -425,7 +505,7 @@ class Pipeline:
425
505
  return None
426
506
 
427
507
  with open(metadata_path) as fp:
428
- config = yaml.full_load(fp) or {}
508
+ config = load_yaml(fp) or {}
429
509
  return config
430
510
 
431
511
  @classmethod
@@ -434,12 +514,17 @@ class Pipeline:
434
514
  uuid,
435
515
  repo_path: str = None,
436
516
  all_projects: bool = False,
517
+ context_data: Dict = None,
437
518
  use_repo_path: bool = False,
438
519
  ) -> Tuple[str, str]:
439
520
  if all_projects and not use_repo_path and project_platform_activated():
440
521
  from mage_ai.settings.platform.utils import get_pipeline_config_path
441
522
 
442
- config_path, repo_path = get_pipeline_config_path(uuid)
523
+ config_path, repo_path = get_pipeline_config_path(
524
+ uuid,
525
+ context_data=context_data,
526
+ repo_path=repo_path,
527
+ )
443
528
  else:
444
529
  repo_path = repo_path or get_repo_path()
445
530
  config_path = os.path.join(
@@ -479,7 +564,7 @@ class Pipeline:
479
564
 
480
565
  config = None
481
566
  async with aiofiles.open(config_path, mode='r') as f:
482
- config = yaml.safe_load(await f.read()) or {}
567
+ config = load_yaml(await f.read()) or {}
483
568
  except Exception as e:
484
569
  if raise_exception:
485
570
  raise e
@@ -496,16 +581,19 @@ class Pipeline:
496
581
  uuid,
497
582
  repo_path: str = None,
498
583
  all_projects: bool = False,
584
+ context_data: Dict = None,
499
585
  use_repo_path: bool = False,
500
586
  ):
501
- from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
502
- IntegrationPipeline,
503
- )
587
+ warn_for_repo_path(repo_path)
504
588
 
505
589
  if all_projects and not use_repo_path and project_platform_activated():
506
590
  from mage_ai.settings.platform.utils import get_pipeline_config_path
507
591
 
508
- config_path, repo_path = get_pipeline_config_path(uuid)
592
+ config_path, repo_path = get_pipeline_config_path(
593
+ uuid,
594
+ context_data=context_data,
595
+ repo_path=repo_path,
596
+ )
509
597
  else:
510
598
  repo_path = repo_path or get_repo_path()
511
599
  config_path = os.path.join(
@@ -515,12 +603,16 @@ class Pipeline:
515
603
  PIPELINE_CONFIG_FILE,
516
604
  )
517
605
 
518
- if not os.path.exists(config_path):
606
+ if not config_path or not os.path.exists(config_path):
519
607
  raise Exception(f'Pipeline {uuid} does not exist.')
520
608
  async with aiofiles.open(config_path, mode='r', encoding='utf-8') as f:
521
- config = yaml.safe_load(await f.read()) or {}
609
+ config = load_yaml(await f.read()) or {}
522
610
 
523
611
  if PipelineType.INTEGRATION == config.get('type'):
612
+ from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
613
+ IntegrationPipeline,
614
+ )
615
+
524
616
  catalog = None
525
617
  catalog_config_path = os.path.join(
526
618
  repo_path,
@@ -554,9 +646,15 @@ class Pipeline:
554
646
  **kwargs,
555
647
  ) -> Union[List[str], List[Tuple[str, str]]]:
556
648
  if project_platform_activated():
557
- repo_paths = [d.get(
558
- 'full_path',
559
- ) for d in build_repo_path_for_all_projects(mage_projects_only=True).values()]
649
+ repo_paths = [
650
+ d.get(
651
+ 'full_path',
652
+ )
653
+ for d in build_repo_path_for_all_projects(
654
+ context_data=kwargs.get('context_data'),
655
+ mage_projects_only=True
656
+ ).values()
657
+ ]
560
658
 
561
659
  return Pipeline.get_all_pipelines(
562
660
  *args,
@@ -572,6 +670,7 @@ class Pipeline:
572
670
  repo_paths: List[str] = None,
573
671
  disable_pipelines_folder_creation: bool = False,
574
672
  include_repo_path: bool = False,
673
+ **kwargs,
575
674
  ) -> Union[List[str], List[Tuple[str, str]]]:
576
675
  arr = []
577
676
 
@@ -581,7 +680,7 @@ class Pipeline:
581
680
  if repo_paths:
582
681
  paths.extend(repo_paths)
583
682
 
584
- for path in paths:
683
+ for path in set(paths):
585
684
  pipelines_folder = os.path.join(path, PIPELINES_FOLDER)
586
685
  pipelines_folder_exists = os.path.exists(pipelines_folder)
587
686
  if not pipelines_folder_exists and not disable_pipelines_folder_creation:
@@ -599,7 +698,10 @@ class Pipeline:
599
698
  return arr
600
699
 
601
700
  @classmethod
602
- def get_pipelines_by_block(self, block, repo_path=None, widget=False) -> List['Pipeline']:
701
+ def get_pipelines_by_block(
702
+ self, block, repo_path: str = None, widget=False
703
+ ) -> List['Pipeline']:
704
+ warn_for_repo_path(repo_path)
603
705
  repo_path = repo_path or get_repo_path()
604
706
  pipelines_folder = os.path.join(repo_path, PIPELINES_FOLDER)
605
707
  pipelines = []
@@ -690,6 +792,7 @@ class Pipeline:
690
792
  from mage_ai.data_preparation.executors.streaming_pipeline_executor import (
691
793
  StreamingPipelineExecutor,
692
794
  )
795
+
693
796
  StreamingPipelineExecutor(self).execute(
694
797
  build_block_output_stdout=build_block_output_stdout,
695
798
  global_vars=global_vars,
@@ -721,7 +824,7 @@ class Pipeline:
721
824
  if not os.path.exists(self.config_path):
722
825
  raise Exception(f'Pipeline {self.uuid} does not exist in repo_path {self.repo_path}.')
723
826
  with open(self.config_path, encoding='utf-8') as fp:
724
- config = yaml.full_load(fp) or {}
827
+ config = load_yaml(fp) or {}
725
828
  return config
726
829
 
727
830
  def get_catalog_from_json(self):
@@ -790,7 +893,9 @@ class Pipeline:
790
893
 
791
894
  language = c.get('language')
792
895
 
793
- return BlockFactory.block_class_from_type(block_type, language=language, pipeline=self)(
896
+ return BlockFactory.block_class_from_type(
897
+ block_type, language=language, pipeline=self
898
+ )(
794
899
  c.get('name'),
795
900
  c.get('uuid'),
796
901
  block_type,
@@ -839,17 +944,28 @@ class Pipeline:
839
944
 
840
945
  for extension_uuid, extension_config in config.get('extensions', {}).items():
841
946
  extension_configs = extension_config.get('blocks') or []
842
- extension_blocks = [build_shared_args_kwargs(merge_dict(c, dict(
843
- extension_uuid=extension_uuid,
844
- ))) for c in extension_configs]
947
+ extension_blocks = [
948
+ build_shared_args_kwargs(
949
+ merge_dict(
950
+ c,
951
+ dict(
952
+ extension_uuid=extension_uuid,
953
+ ),
954
+ )
955
+ )
956
+ for c in extension_configs
957
+ ]
845
958
 
846
- self.extensions[extension_uuid] = merge_dict(extension_config, dict(
847
- blocks_by_uuid=self.__initialize_blocks_by_uuid(
848
- extension_configs,
849
- extension_blocks,
850
- all_blocks,
959
+ self.extensions[extension_uuid] = merge_dict(
960
+ extension_config,
961
+ dict(
962
+ blocks_by_uuid=self.__initialize_blocks_by_uuid(
963
+ extension_configs,
964
+ extension_blocks,
965
+ all_blocks,
966
+ ),
851
967
  ),
852
- ))
968
+ )
853
969
 
854
970
  blocks_with_callbacks = {}
855
971
  for callback_block in self.callbacks_by_uuid.values():
@@ -883,11 +999,13 @@ class Pipeline:
883
999
  for b in configs:
884
1000
  block = blocks_by_uuid[b['uuid']]
885
1001
  block.downstream_blocks = [
886
- all_blocks_by_uuid[uuid] for uuid in b.get('downstream_blocks', [])
1002
+ all_blocks_by_uuid[uuid]
1003
+ for uuid in b.get('downstream_blocks', [])
887
1004
  if uuid in all_blocks_by_uuid
888
1005
  ]
889
1006
  block.upstream_blocks = [
890
- all_blocks_by_uuid[uuid] for uuid in b.get('upstream_blocks', [])
1007
+ all_blocks_by_uuid[uuid]
1008
+ for uuid in b.get('upstream_blocks', [])
891
1009
  if uuid in all_blocks_by_uuid
892
1010
  ]
893
1011
 
@@ -941,7 +1059,9 @@ class Pipeline:
941
1059
 
942
1060
  blocks_data = [b.to_dict(**shared_kwargs) for b in self.blocks_by_uuid.values()]
943
1061
  callbacks_data = [b.to_dict(**shared_kwargs) for b in self.callbacks_by_uuid.values()]
944
- conditionals_data = [b.to_dict(**shared_kwargs) for b in self.conditionals_by_uuid.values()]
1062
+ conditionals_data = [
1063
+ b.to_dict(**shared_kwargs) for b in self.conditionals_by_uuid.values()
1064
+ ]
945
1065
  widgets_data = [b.to_dict(**shared_kwargs) for b in self.widgets_by_uuid.values()]
946
1066
 
947
1067
  data = dict(
@@ -962,13 +1082,17 @@ class Pipeline:
962
1082
  include_outputs=include_outputs,
963
1083
  include_outputs_spark=include_outputs_spark,
964
1084
  sample_count=sample_count,
965
- ) for b in extension['blocks_by_uuid'].values()
1085
+ )
1086
+ for b in extension['blocks_by_uuid'].values()
966
1087
  ]
967
1088
  extensions_data[extension_uuid] = merge_dict(
968
- ignore_keys(extension, [
969
- 'blocks',
970
- 'blocks_by_uuid',
971
- ]),
1089
+ ignore_keys(
1090
+ extension,
1091
+ [
1092
+ 'blocks',
1093
+ 'blocks_by_uuid',
1094
+ ],
1095
+ ),
972
1096
  dict(
973
1097
  blocks=blocks,
974
1098
  ),
@@ -992,7 +1116,10 @@ class Pipeline:
992
1116
  include_extensions: bool = False,
993
1117
  include_outputs: bool = False,
994
1118
  include_outputs_spark: bool = False,
995
- sample_count: int = None,
1119
+ sample_count: Optional[int] = None,
1120
+ disable_block_output_previews: bool = False,
1121
+ exclude_blank_variable_uuids: bool = False,
1122
+ max_results: Optional[int] = None,
996
1123
  ):
997
1124
  shared_kwargs = dict(
998
1125
  check_if_file_exists=True,
@@ -1006,26 +1133,36 @@ class Pipeline:
1006
1133
  )
1007
1134
  if include_block_pipelines:
1008
1135
  shared_kwargs['block_cache'] = BlockCache()
1009
- blocks_data = await asyncio.gather(
1010
- *[b.to_dict_async(**merge_dict(shared_kwargs, dict(
1011
- include_block_catalog=include_block_catalog,
1012
- include_block_pipelines=include_block_pipelines,
1013
- include_outputs_spark=include_outputs_spark,
1014
- ))) for b in self.blocks_by_uuid.values()]
1015
- )
1016
- callbacks_data = await asyncio.gather(
1017
- *[b.to_dict_async(**shared_kwargs) for b in self.callbacks_by_uuid.values()]
1018
- )
1019
- conditionals_data = await asyncio.gather(
1020
- *[b.to_dict_async(**shared_kwargs) for b in self.conditionals_by_uuid.values()]
1021
- )
1022
- widgets_data = await asyncio.gather(
1023
- *[b.to_dict_async(
1136
+ blocks_data = await asyncio.gather(*[
1137
+ b.to_dict_async(
1138
+ **merge_dict(
1139
+ shared_kwargs,
1140
+ dict(
1141
+ include_block_catalog=include_block_catalog,
1142
+ include_block_pipelines=include_block_pipelines,
1143
+ include_outputs_spark=include_outputs_spark,
1144
+ disable_output_preview=disable_block_output_previews,
1145
+ exclude_blank_variable_uuids=exclude_blank_variable_uuids,
1146
+ max_results=max_results,
1147
+ ),
1148
+ )
1149
+ )
1150
+ for b in self.blocks_by_uuid.values()
1151
+ ])
1152
+ callbacks_data = await asyncio.gather(*[
1153
+ b.to_dict_async(**shared_kwargs) for b in self.callbacks_by_uuid.values()
1154
+ ])
1155
+ conditionals_data = await asyncio.gather(*[
1156
+ b.to_dict_async(**shared_kwargs) for b in self.conditionals_by_uuid.values()
1157
+ ])
1158
+ widgets_data = await asyncio.gather(*[
1159
+ b.to_dict_async(
1024
1160
  include_content=include_content,
1025
1161
  include_outputs=include_outputs,
1026
1162
  sample_count=sample_count,
1027
- ) for b in self.widgets_by_uuid.values()]
1028
- )
1163
+ )
1164
+ for b in self.widgets_by_uuid.values()
1165
+ ])
1029
1166
  data = dict(
1030
1167
  blocks=blocks_data,
1031
1168
  callbacks=callbacks_data,
@@ -1038,18 +1175,22 @@ class Pipeline:
1038
1175
  for extension_uuid, extension in self.extensions.items():
1039
1176
  blocks = []
1040
1177
  if 'blocks_by_uuid' in extension:
1041
- blocks = await asyncio.gather(
1042
- *[b.to_dict_async(
1178
+ blocks = await asyncio.gather(*[
1179
+ b.to_dict_async(
1043
1180
  include_content=include_content,
1044
1181
  include_outputs=include_outputs,
1045
1182
  sample_count=sample_count,
1046
- ) for b in extension['blocks_by_uuid'].values()]
1047
- )
1183
+ )
1184
+ for b in extension['blocks_by_uuid'].values()
1185
+ ])
1048
1186
  extensions_data[extension_uuid] = merge_dict(
1049
- ignore_keys(extension, [
1050
- 'blocks',
1051
- 'blocks_by_uuid',
1052
- ]),
1187
+ ignore_keys(
1188
+ extension,
1189
+ [
1190
+ 'blocks',
1191
+ 'blocks_by_uuid',
1192
+ ],
1193
+ ),
1053
1194
  dict(
1054
1195
  blocks=blocks,
1055
1196
  ),
@@ -1087,6 +1228,8 @@ class Pipeline:
1087
1228
  self.uuid = new_uuid
1088
1229
  new_pipeline_path = self.dir_path
1089
1230
  os.rename(old_pipeline_path, new_pipeline_path)
1231
+ # Force updating the config path
1232
+ self._config_path = None
1090
1233
  await self.save_async()
1091
1234
  transfer_related_models_for_pipeline(old_uuid, new_uuid)
1092
1235
 
@@ -1100,7 +1243,7 @@ class Pipeline:
1100
1243
  should_update_tag_cache = True
1101
1244
 
1102
1245
  cache = PipelineCache()
1103
- cache.move_model(dict(uuid=new_uuid), dict(uuid=old_uuid))
1246
+ cache.move_model(dict(uuid=new_uuid), dict(uuid=old_uuid), repo_path=self.repo_path)
1104
1247
 
1105
1248
  should_save = False
1106
1249
 
@@ -1108,11 +1251,12 @@ class Pipeline:
1108
1251
  for extension_uuid, extension in data['extensions'].items():
1109
1252
  if extension_uuid not in self.extensions:
1110
1253
  self.extensions[extension_uuid] = {}
1111
- self.extensions[extension_uuid] = merge_dict(
1112
- self.extensions[extension_uuid],
1113
- extension,
1114
- )
1115
- should_save = True
1254
+ if compare_extension(extension, self.extensions[extension_uuid]):
1255
+ self.extensions[extension_uuid] = merge_dict(
1256
+ self.extensions[extension_uuid],
1257
+ extension,
1258
+ )
1259
+ should_save = True
1116
1260
 
1117
1261
  if 'tags' in data:
1118
1262
  new_tags = data.get('tags', [])
@@ -1138,16 +1282,17 @@ class Pipeline:
1138
1282
 
1139
1283
  for key in [
1140
1284
  'cache_block_output_in_memory',
1285
+ 'concurrency_config',
1141
1286
  'data_integration',
1142
1287
  'executor_type',
1143
1288
  'retry_config',
1144
1289
  'run_pipeline_in_one_process',
1145
1290
  ]:
1146
- if key in data:
1291
+ if key in data and data.get(key) != getattr(self, key):
1147
1292
  setattr(self, key, data.get(key))
1148
1293
  should_save = True
1149
1294
 
1150
- if 'settings' in data:
1295
+ if 'settings' in data and data.get('settings') != self.settings.to_dict():
1151
1296
  self.settings = PipelineSettings.load(**(data.get('settings') or {}))
1152
1297
  should_save = True
1153
1298
 
@@ -1225,7 +1370,7 @@ class Pipeline:
1225
1370
  )
1226
1371
 
1227
1372
  if hooks:
1228
- for hook in (hooks or []):
1373
+ for hook in hooks or []:
1229
1374
  output = hook.output
1230
1375
  if not output:
1231
1376
  continue
@@ -1243,25 +1388,31 @@ class Pipeline:
1243
1388
  old_block_content = await block.content_async()
1244
1389
  if block_data['content'] != old_block_content:
1245
1390
  if cache_block_action_object is None:
1246
- cache_block_action_object = \
1391
+ cache_block_action_object = (
1247
1392
  await BlockActionObjectCache.initialize_cache()
1393
+ )
1248
1394
 
1249
1395
  await block.update_content_async(block_data['content'], widget=widget)
1250
1396
 
1251
1397
  cache_block_action_object.update_block(block)
1252
1398
 
1253
- if 'callback_content' in block_data \
1254
- and block.callback_block:
1399
+ if 'callback_content' in block_data and block.callback_block:
1255
1400
  await block.callback_block.update_content_async(
1256
1401
  block_data['callback_content'],
1257
1402
  widget=widget,
1258
1403
  )
1259
- if 'outputs' in block_data:
1260
- if not is_dynamic_block(block) and not is_dynamic_block_child(block):
1261
- await block.save_outputs_async(
1262
- block_data['outputs'],
1263
- override=True,
1264
- )
1404
+ if (
1405
+ 'outputs' in block_data
1406
+ and not widget
1407
+ and not is_dynamic_block(block)
1408
+ and not is_dynamic_block_child(block)
1409
+ ):
1410
+ if BlockType.SCRATCHPAD == block.type:
1411
+ block.delete_variables()
1412
+ await block.save_outputs_async(
1413
+ block_data['outputs'],
1414
+ override=True,
1415
+ )
1265
1416
 
1266
1417
  name = block_data.get('name')
1267
1418
 
@@ -1273,7 +1424,7 @@ class Pipeline:
1273
1424
  block.update(extract(block_data, ['color']))
1274
1425
 
1275
1426
  configuration = block_data.get('configuration')
1276
- if configuration:
1427
+ if configuration and configuration != block.configuration:
1277
1428
  block.configuration = configuration
1278
1429
  should_save_async = should_save_async or True
1279
1430
 
@@ -1283,42 +1434,50 @@ class Pipeline:
1283
1434
  if name and name != block.name:
1284
1435
  keys_to_update.append('name')
1285
1436
 
1286
- if block_data.get('upstream_blocks'):
1437
+ upstream_blocks = block_data.get('upstream_blocks') or []
1438
+ if upstream_blocks != block.upstream_block_uuids:
1287
1439
  keys_to_update.append('upstream_blocks')
1288
1440
  block_data['upstream_blocks'] = [
1289
- block_uuid_mapping.get(b, b)
1290
- for b in block_data['upstream_blocks']
1441
+ block_uuid_mapping.get(b, b) for b in block_data['upstream_blocks']
1291
1442
  ]
1292
-
1293
1443
  if len(keys_to_update) >= 1:
1294
1444
  block.update(extract(block_data, keys_to_update))
1445
+ should_save_async = should_save_async or True
1295
1446
 
1296
- should_save_async = should_save_async or True
1297
1447
  elif name and name != block.name:
1298
1448
  from mage_ai.cache.block_action_object import (
1299
1449
  BlockActionObjectCache,
1300
1450
  )
1301
1451
 
1302
1452
  if cache_block_action_object is None:
1303
- cache_block_action_object = \
1453
+ cache_block_action_object = (
1304
1454
  await BlockActionObjectCache.initialize_cache()
1455
+ )
1305
1456
  cache_block_action_object.update_block(block, remove=True)
1306
1457
 
1458
+ new_block_uuid = clean_name(name)
1459
+ (
1460
+ old_file_path,
1461
+ old_file_path_relative,
1462
+ ) = block.build_file_path_directory()
1463
+ (
1464
+ new_file_path,
1465
+ new_file_path_relative,
1466
+ ) = block.build_file_path_directory(
1467
+ block_uuid=new_block_uuid,
1468
+ )
1469
+
1307
1470
  block_update_payload = extract(block_data, ['name'])
1308
- configuration = copy.deepcopy(block_data).get('configuration', {})
1309
- file_path = (configuration.get('file_source') or {}).get('path')
1310
- if file_path:
1311
- # Check for block name with period to avoid replacing a directory name
1312
- new_file_path = file_path.replace(
1313
- f'{clean_name(block.name)}.', f'{clean_name(name)}.'
1314
- )
1315
- configuration['file_source']['path'] = new_file_path
1316
- block_update_payload['configuration'] = configuration
1471
+ configuration = copy.deepcopy(block_data).get('configuration', {}) or {}
1472
+ configuration['file_path'] = new_file_path_relative
1473
+
1474
+ if not configuration.get('file_source'):
1475
+ configuration['file_source'] = {}
1476
+ configuration['file_source']['path'] = new_file_path_relative
1477
+ block_update_payload['configuration'] = configuration
1478
+
1317
1479
  blocks_to_remove_from_cache.append(block.to_dict())
1318
- block.update(
1319
- block_update_payload,
1320
- detach=block_data.get('detach', False)
1321
- )
1480
+ block.update(block_update_payload, detach=block_data.get('detach', False))
1322
1481
 
1323
1482
  block_uuids_to_add_to_cache.append(block.uuid)
1324
1483
  cache_block_action_object.update_block(block)
@@ -1336,9 +1495,9 @@ class Pipeline:
1336
1495
  # we need to update mage_sources.yml
1337
1496
  if any(
1338
1497
  (
1339
- BlockType.DBT != block.type and
1340
- block.language in [BlockLanguage.SQL, BlockLanguage.PYTHON, BlockLanguage.R] and
1341
- any(
1498
+ BlockType.DBT != block.type
1499
+ and block.language in [BlockLanguage.SQL, BlockLanguage.PYTHON, BlockLanguage.R]
1500
+ and any(
1342
1501
  BlockType.DBT == downstream_block.type
1343
1502
  for downstream_block in block.downstream_blocks
1344
1503
  )
@@ -1371,7 +1530,7 @@ class Pipeline:
1371
1530
  old_uuid,
1372
1531
  self.repo_path,
1373
1532
  )
1374
- cache.update_pipeline(block.to_dict(), self)
1533
+ cache.update_pipeline(block.to_dict(), self, self.repo_path)
1375
1534
 
1376
1535
  if should_update_tag_cache:
1377
1536
  from mage_ai.cache.tag import TagCache
@@ -1453,8 +1612,7 @@ class Pipeline:
1453
1612
 
1454
1613
  files_to_be_written = []
1455
1614
  with open(config_zip_path, 'r') as pipeline_config:
1456
-
1457
- config = yaml.safe_load(pipeline_config)
1615
+ config = load_yaml(pipeline_config)
1458
1616
 
1459
1617
  # check if pipeline exists with same uuid and generate new one if necessary
1460
1618
  if not overwrite:
@@ -1564,8 +1722,10 @@ class Pipeline:
1564
1722
 
1565
1723
  if block_uuid in self.blocks_by_uuid:
1566
1724
  block = self.blocks_by_uuid[block_uuid]
1567
- if upstream_blocks_reordered is not None and \
1568
- upstream_blocks != upstream_blocks_reordered:
1725
+ if (
1726
+ upstream_blocks_reordered is not None
1727
+ and upstream_blocks != upstream_blocks_reordered
1728
+ ):
1569
1729
  block.update(
1570
1730
  dict(upstream_blocks=upstream_blocks_reordered),
1571
1731
  check_upstream_block_order=True,
@@ -1613,7 +1773,8 @@ class Pipeline:
1613
1773
  all_block_uuids = {b.get('uuid') for b in self.all_block_configs}
1614
1774
  if block.uuid in all_block_uuids:
1615
1775
  raise InvalidPipelineError(
1616
- f'Block with uuid {block.uuid} already exists in pipeline {self.uuid}')
1776
+ f'Block with uuid {block.uuid} already exists in pipeline {self.uuid}'
1777
+ )
1617
1778
 
1618
1779
  if widget:
1619
1780
  self.widgets_by_uuid = self.__add_block_to_mapping(
@@ -1666,9 +1827,8 @@ class Pipeline:
1666
1827
 
1667
1828
  self.update_block(
1668
1829
  downstream_block,
1669
- upstream_block_uuids=(
1670
- downstream_block.upstream_block_uuids or []
1671
- ) + [block.uuid],
1830
+ upstream_block_uuids=(downstream_block.upstream_block_uuids or [])
1831
+ + [block.uuid],
1672
1832
  )
1673
1833
 
1674
1834
  self.validate('A cycle was formed while adding a block')
@@ -1728,9 +1888,13 @@ class Pipeline:
1728
1888
  sample_count: int = None,
1729
1889
  dynamic_block_index: int = None,
1730
1890
  dynamic_block_uuid: str = None,
1891
+ input_data_types: Optional[List[InputDataType]] = None,
1892
+ read_batch_settings: Optional[BatchSettings] = None,
1893
+ read_chunks: Optional[List[ChunkKeyTypeUnion]] = None,
1894
+ write_batch_settings: Optional[BatchSettings] = None,
1895
+ write_chunks: Optional[List[ChunkKeyTypeUnion]] = None,
1731
1896
  ):
1732
1897
  block = self.get_block(block_uuid)
1733
-
1734
1898
  data_integration_settings = block.get_data_integration_settings(
1735
1899
  from_notebook=from_notebook,
1736
1900
  global_vars=global_vars,
@@ -1758,6 +1922,11 @@ class Pipeline:
1758
1922
  variable_uuid=variable_name,
1759
1923
  dynamic_block_index=dynamic_block_index,
1760
1924
  dynamic_block_uuid=dynamic_block_uuid,
1925
+ input_data_types=input_data_types,
1926
+ read_batch_settings=read_batch_settings,
1927
+ read_chunks=read_chunks,
1928
+ write_batch_settings=write_batch_settings,
1929
+ write_chunks=write_chunks,
1761
1930
  )
1762
1931
 
1763
1932
  return variable
@@ -1779,10 +1948,12 @@ class Pipeline:
1779
1948
 
1780
1949
  def has_block(self, block_uuid: str, block_type: str = None, extension_uuid: str = None):
1781
1950
  if extension_uuid:
1782
- return self.extensions and \
1783
- extension_uuid in self.extensions and \
1784
- 'blocks_by_uuid' in self.extensions[extension_uuid] and \
1785
- block_uuid in self.extensions[extension_uuid]['blocks_by_uuid']
1951
+ return (
1952
+ self.extensions
1953
+ and extension_uuid in self.extensions
1954
+ and 'blocks_by_uuid' in self.extensions[extension_uuid]
1955
+ and block_uuid in self.extensions[extension_uuid]['blocks_by_uuid']
1956
+ )
1786
1957
  elif BlockType.CALLBACK == block_type:
1787
1958
  return block_uuid in self.callbacks_by_uuid
1788
1959
  elif BlockType.CONDITIONAL == block_type:
@@ -1810,9 +1981,9 @@ class Pipeline:
1810
1981
  if upstream_block_uuids is not None:
1811
1982
  curr_upstream_block_uuids = set(block.upstream_block_uuids)
1812
1983
  new_upstream_block_uuids = set(upstream_block_uuids)
1813
- if curr_upstream_block_uuids != new_upstream_block_uuids or \
1814
- (check_upstream_block_order and
1815
- block.upstream_block_uuids != upstream_block_uuids):
1984
+ if curr_upstream_block_uuids != new_upstream_block_uuids or (
1985
+ check_upstream_block_order and block.upstream_block_uuids != upstream_block_uuids
1986
+ ):
1816
1987
  # Only set upstream block’s downstream to the current block if current block
1817
1988
  # is not an extension block and not a callback/conditional block
1818
1989
  if not is_extension and not is_callback and not is_conditional:
@@ -1871,9 +2042,9 @@ class Pipeline:
1871
2042
  # conditional_blocks field.
1872
2043
  block.update_conditional_blocks(conditional_blocks)
1873
2044
  elif downstream_block_uuids is not None:
1874
- block_uuids_to_remove = \
1875
- [uuid for uuid in block.downstream_block_uuids
1876
- if uuid not in downstream_block_uuids]
2045
+ block_uuids_to_remove = [
2046
+ uuid for uuid in block.downstream_block_uuids if uuid not in downstream_block_uuids
2047
+ ]
1877
2048
 
1878
2049
  for block_uuid in block_uuids_to_remove:
1879
2050
  block_inner = self.get_block(block_uuid)
@@ -1881,10 +2052,12 @@ class Pipeline:
1881
2052
  continue
1882
2053
  block_inner.update(
1883
2054
  dict(
1884
- upstream_blocks=list(filter(
1885
- lambda x, uuid=block.uuid: x != uuid,
1886
- block_inner.upstream_block_uuids or [],
1887
- )),
2055
+ upstream_blocks=list(
2056
+ filter(
2057
+ lambda x, uuid=block.uuid: x != uuid,
2058
+ block_inner.upstream_block_uuids or [],
2059
+ )
2060
+ ),
1888
2061
  ),
1889
2062
  check_upstream_block_order=check_upstream_block_order,
1890
2063
  )
@@ -1992,7 +2165,8 @@ class Pipeline:
1992
2165
  def update_global_variable(self, key, value):
1993
2166
  if not is_yaml_serializable(key, value):
1994
2167
  raise SerializationError(
1995
- f'Failed to update variable {key} because the value is not serializable.')
2168
+ f'Failed to update variable {key} because the value is not serializable.'
2169
+ )
1996
2170
  if self.variables is None:
1997
2171
  self.variables = {}
1998
2172
  self.variables[key] = value
@@ -2055,13 +2229,20 @@ class Pipeline:
2055
2229
  ]
2056
2230
  if self.type == PipelineType.INTEGRATION or force:
2057
2231
  for downstream_block in block.downstream_blocks:
2058
- upstream_block_uuids = list(filter(
2059
- lambda uuid: uuid != block.uuid,
2060
- downstream_block.upstream_block_uuids
2061
- ))
2062
- downstream_block.update(dict(
2063
- upstream_blocks=[*upstream_block_uuids, *block.upstream_block_uuids]
2064
- ))
2232
+ upstream_block_uuids = list(
2233
+ filter(
2234
+ lambda uuid: uuid != block.uuid,
2235
+ downstream_block.upstream_block_uuids,
2236
+ )
2237
+ )
2238
+ downstream_block.update(
2239
+ dict(
2240
+ upstream_blocks=[
2241
+ *upstream_block_uuids,
2242
+ *block.upstream_block_uuids,
2243
+ ]
2244
+ )
2245
+ )
2065
2246
  elif len(downstream_block_uuids) > 0:
2066
2247
  raise HasDownstreamDependencies(
2067
2248
  f'Block(s) {downstream_block_uuids} are depending on block {block.uuid}'
@@ -2111,7 +2292,7 @@ class Pipeline:
2111
2292
  blocks_current = sorted([b.uuid for b in self.blocks_by_uuid.values()])
2112
2293
 
2113
2294
  if block_uuid is not None:
2114
- current_pipeline = Pipeline(self.uuid, self.repo_path)
2295
+ current_pipeline = Pipeline(self.uuid, repo_path=self.repo_path)
2115
2296
  block = self.get_block(
2116
2297
  block_uuid,
2117
2298
  block_type=block_type,
@@ -2167,18 +2348,21 @@ class Pipeline:
2167
2348
  def should_save_trigger_in_code_automatically(self) -> bool:
2168
2349
  from mage_ai.data_preparation.models.project import Project
2169
2350
 
2170
- if self.settings and \
2171
- self.settings.triggers and \
2172
- self.settings.triggers.save_in_code_automatically is not None:
2173
-
2351
+ if (
2352
+ self.settings
2353
+ and self.settings.triggers
2354
+ and self.settings.triggers.save_in_code_automatically is not None
2355
+ ):
2174
2356
  return self.settings.triggers.save_in_code_automatically
2175
2357
 
2176
- project = Project(self.repo_config)
2358
+ project = Project(repo_config=self.repo_config)
2177
2359
 
2178
- return project.pipelines and \
2179
- project.pipelines.settings and \
2180
- project.pipelines.settings.triggers and \
2181
- project.pipelines.settings.triggers.save_in_code_automatically
2360
+ return (
2361
+ project.pipelines
2362
+ and project.pipelines.settings
2363
+ and project.pipelines.settings.triggers
2364
+ and project.pipelines.settings.triggers.save_in_code_automatically
2365
+ )
2182
2366
 
2183
2367
  async def save_async(
2184
2368
  self,
@@ -2235,7 +2419,7 @@ class Pipeline:
2235
2419
  success = True
2236
2420
  with open(test_path, mode='r', encoding='utf-8') as fp:
2237
2421
  try:
2238
- yaml.full_load(fp)
2422
+ load_yaml(fp)
2239
2423
  except yaml.scanner.ScannerError:
2240
2424
  success = False
2241
2425
 
@@ -2285,7 +2469,7 @@ class Pipeline:
2285
2469
  index += 1
2286
2470
 
2287
2471
  cycle = [frame.uuid for frame in virtual_stack[index:]]
2288
- return " --> ".join(cycle)
2472
+ return ' --> '.join(cycle)
2289
2473
 
2290
2474
  def __check_cycle(block: Block):
2291
2475
  virtual_stack = [StackFrame(block)]
@@ -2316,7 +2500,8 @@ class Pipeline:
2316
2500
  uuid = config.get('uuid')
2317
2501
  if uuid in check_block_uuids:
2318
2502
  raise InvalidPipelineError(
2319
- f'Pipeline is invalid: duplicate blocks with uuid {uuid}')
2503
+ f'Pipeline is invalid: duplicate blocks with uuid {uuid}'
2504
+ )
2320
2505
  check_block_uuids.add(uuid)
2321
2506
 
2322
2507