mage-ai 0.9.69__py3-none-any.whl → 0.9.70__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 (243) hide show
  1. mage_ai/api/policies/BackfillPolicy.py +1 -0
  2. mage_ai/api/policies/PipelinePolicy.py +1 -0
  3. mage_ai/api/policies/WorkspacePolicy.py +1 -0
  4. mage_ai/api/presenters/BackfillPresenter.py +1 -0
  5. mage_ai/api/resources/GitBranchResource.py +56 -23
  6. mage_ai/api/resources/GitCustomBranchResource.py +29 -1
  7. mage_ai/api/resources/OauthResource.py +1 -1
  8. mage_ai/api/resources/PipelineResource.py +11 -5
  9. mage_ai/api/resources/PipelineRunResource.py +41 -4
  10. mage_ai/api/resources/PipelineScheduleResource.py +4 -0
  11. mage_ai/api/resources/PullRequestResource.py +6 -4
  12. mage_ai/api/resources/WorkspaceResource.py +5 -4
  13. mage_ai/cache/block_action_object/__init__.py +1 -1
  14. mage_ai/cluster_manager/kubernetes/workload_manager.py +52 -1
  15. mage_ai/cluster_manager/workspace/base.py +6 -0
  16. mage_ai/cluster_manager/workspace/kubernetes.py +22 -1
  17. mage_ai/command_center/applications/utils.py +2 -2
  18. mage_ai/command_center/presenters/text.py +1 -1
  19. mage_ai/data_preparation/executors/k8s_block_executor.py +30 -7
  20. mage_ai/data_preparation/executors/k8s_pipeline_executor.py +30 -7
  21. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +1 -1
  22. mage_ai/data_preparation/git/__init__.py +50 -22
  23. mage_ai/data_preparation/git/api.py +62 -7
  24. mage_ai/data_preparation/git/utils.py +45 -21
  25. mage_ai/data_preparation/models/block/__init__.py +24 -5
  26. mage_ai/data_preparation/models/block/dynamic/utils.py +9 -4
  27. mage_ai/data_preparation/models/block/global_data_product/__init__.py +25 -2
  28. mage_ai/data_preparation/models/block/remote/__init__.py +0 -0
  29. mage_ai/data_preparation/models/block/remote/models.py +58 -0
  30. mage_ai/data_preparation/models/block/utils.py +38 -0
  31. mage_ai/data_preparation/models/constants.py +2 -0
  32. mage_ai/data_preparation/models/global_data_product/__init__.py +12 -0
  33. mage_ai/data_preparation/models/pipeline.py +9 -5
  34. mage_ai/data_preparation/models/triggers/__init__.py +4 -2
  35. mage_ai/data_preparation/storage/local_storage.py +12 -6
  36. mage_ai/orchestration/db/migrations/versions/42a14d6143f1_update_token_column_type.py +54 -0
  37. mage_ai/orchestration/db/models/oauth.py +10 -9
  38. mage_ai/orchestration/db/models/schedules.py +21 -0
  39. mage_ai/orchestration/notification/sender.py +37 -15
  40. mage_ai/orchestration/pipeline_scheduler_original.py +32 -25
  41. mage_ai/orchestration/triggers/api.py +29 -1
  42. mage_ai/orchestration/triggers/global_data_product.py +9 -4
  43. mage_ai/orchestration/triggers/utils.py +10 -1
  44. mage_ai/orchestration/utils/resources.py +3 -0
  45. mage_ai/server/api/downloads.py +4 -1
  46. mage_ai/server/api/runs.py +151 -0
  47. mage_ai/server/constants.py +1 -1
  48. mage_ai/server/frontend_dist/404.html +6 -6
  49. mage_ai/server/frontend_dist/_next/static/{_krrrgup_C-dPOpX36S8I → RhDiJSkcjCsh4xxX4BFBk}/_buildManifest.js +1 -1
  50. mage_ai/server/frontend_dist/_next/static/chunks/1557-b3502f3f1aa92ac7.js +1 -0
  51. mage_ai/server/frontend_dist/_next/static/chunks/{3548-fa0792ddb88f4646.js → 3548-9d26185b3fb663b1.js} +1 -1
  52. mage_ai/server/frontend_dist/_next/static/chunks/7966-b9b85ba10667e654.js +1 -0
  53. mage_ai/server/frontend_dist/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
  54. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +1 -0
  55. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
  56. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-3edc6270c5b0e962.js → frontend_dist/_next/static/chunks/pages/pipeline-runs-6d183f91a2ff6668.js} +1 -1
  57. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7181b086c93784d2.js +1 -0
  58. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
  59. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +1 -0
  60. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-1bdfda8edc9cf4a8.js → triggers-4612d15a65c35912.js} +1 -1
  62. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +1 -0
  64. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +1 -0
  65. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9cba3211434a8966.js → frontend_dist/_next/static/chunks/pages/triggers-a599c6ac89be8c8d.js} +1 -1
  66. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +1 -0
  67. mage_ai/server/frontend_dist/block-layout.html +2 -2
  68. mage_ai/server/frontend_dist/compute.html +2 -2
  69. mage_ai/server/frontend_dist/files.html +2 -2
  70. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  71. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  72. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  73. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  74. mage_ai/server/frontend_dist/index.html +2 -2
  75. mage_ai/server/frontend_dist/manage/files.html +2 -2
  76. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  77. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  78. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  79. mage_ai/server/frontend_dist/manage/users.html +2 -2
  80. mage_ai/server/frontend_dist/manage.html +2 -2
  81. mage_ai/server/frontend_dist/oauth.html +2 -2
  82. mage_ai/server/frontend_dist/overview.html +2 -2
  83. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  84. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  85. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  86. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  87. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  88. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  89. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  90. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  91. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  92. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  93. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  94. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  95. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  96. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  97. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  98. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  99. mage_ai/server/frontend_dist/pipelines.html +2 -2
  100. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  101. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  102. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  103. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  104. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  105. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  106. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  107. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  108. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  109. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  110. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  111. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  112. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  113. mage_ai/server/frontend_dist/settings.html +2 -2
  114. mage_ai/server/frontend_dist/sign-in.html +6 -6
  115. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  116. mage_ai/server/frontend_dist/templates.html +2 -2
  117. mage_ai/server/frontend_dist/terminal.html +2 -2
  118. mage_ai/server/frontend_dist/test.html +2 -2
  119. mage_ai/server/frontend_dist/triggers.html +2 -2
  120. mage_ai/server/frontend_dist/version-control.html +2 -2
  121. mage_ai/server/frontend_dist_base_path_template/404.html +6 -6
  122. mage_ai/server/frontend_dist_base_path_template/_next/static/{KLL5mirre9d7_ZeEpaw3s → TdpLLFome13qvM0gXvpHs}/_buildManifest.js +1 -1
  123. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-b3502f3f1aa92ac7.js +1 -0
  124. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3548-fa0792ddb88f4646.js → 3548-9d26185b3fb663b1.js} +1 -1
  125. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-b9b85ba10667e654.js +1 -0
  126. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
  127. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +1 -0
  128. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
  129. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipeline-runs-3edc6270c5b0e962.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-6d183f91a2ff6668.js} +1 -1
  130. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7181b086c93784d2.js +1 -0
  131. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
  132. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +1 -0
  133. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
  134. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-1bdfda8edc9cf4a8.js → triggers-4612d15a65c35912.js} +1 -1
  135. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js +1 -0
  136. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +1 -0
  137. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +1 -0
  138. mage_ai/server/{frontend_dist/_next/static/chunks/pages/triggers-9cba3211434a8966.js → frontend_dist_base_path_template/_next/static/chunks/pages/triggers-a599c6ac89be8c8d.js} +1 -1
  139. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +1 -0
  140. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  141. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  142. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  143. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  144. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  145. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  146. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  147. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  148. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  149. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  150. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  151. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  152. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  153. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  154. mage_ai/server/frontend_dist_base_path_template/oauth.html +2 -2
  155. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  156. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  157. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  158. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  159. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  160. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  161. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  162. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  163. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  164. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  165. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  166. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  167. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  168. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  169. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  172. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  173. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  181. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  183. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/sign-in.html +6 -6
  188. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  191. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  192. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  193. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  194. mage_ai/server/scheduler_manager.py +3 -1
  195. mage_ai/server/server.py +35 -12
  196. mage_ai/server/utils/output_display.py +2 -2
  197. mage_ai/services/aws/ecs/ecs.py +1 -0
  198. mage_ai/services/k8s/config.py +4 -4
  199. mage_ai/services/k8s/utils.py +97 -0
  200. mage_ai/shared/parsers.py +6 -1
  201. mage_ai/tests/api/operations/base/mixins.py +1 -1
  202. mage_ai/tests/api/resources/test_pipeline_resource.py +2 -2
  203. mage_ai/tests/authentication/oauth/test_utils.py +1 -1
  204. mage_ai/tests/data_preparation/models/block/test_global_data_product.py +2 -0
  205. mage_ai/tests/orchestration/triggers/test_global_data_product.py +138 -136
  206. mage_ai/tests/server/test_server.py +19 -0
  207. mage_ai/tests/services/k8s/test_job_manager.py +9 -6
  208. mage_ai/version_control/branch/utils.py +2 -1
  209. mage_ai/version_control/models.py +3 -2
  210. {mage_ai-0.9.69.dist-info → mage_ai-0.9.70.dist-info}/METADATA +2 -2
  211. {mage_ai-0.9.69.dist-info → mage_ai-0.9.70.dist-info}/RECORD +217 -212
  212. mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +0 -1
  213. mage_ai/server/frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
  214. mage_ai/server/frontend_dist/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
  215. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +0 -1
  216. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
  217. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
  218. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
  219. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +0 -1
  220. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
  221. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +0 -1
  222. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +0 -1
  223. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js +0 -1
  224. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
  225. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +0 -1
  226. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
  227. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
  228. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +0 -1
  229. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
  230. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
  231. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
  232. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +0 -1
  233. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
  234. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +0 -1
  235. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +0 -1
  236. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js +0 -1
  237. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
  238. /mage_ai/server/frontend_dist/_next/static/{_krrrgup_C-dPOpX36S8I → RhDiJSkcjCsh4xxX4BFBk}/_ssgManifest.js +0 -0
  239. /mage_ai/server/frontend_dist_base_path_template/_next/static/{KLL5mirre9d7_ZeEpaw3s → TdpLLFome13qvM0gXvpHs}/_ssgManifest.js +0 -0
  240. {mage_ai-0.9.69.dist-info → mage_ai-0.9.70.dist-info}/LICENSE +0 -0
  241. {mage_ai-0.9.69.dist-info → mage_ai-0.9.70.dist-info}/WHEEL +0 -0
  242. {mage_ai-0.9.69.dist-info → mage_ai-0.9.70.dist-info}/entry_points.txt +0 -0
  243. {mage_ai-0.9.69.dist-info → mage_ai-0.9.70.dist-info}/top_level.txt +0 -0
@@ -6,19 +6,25 @@ from jinja2 import Template
6
6
  from mage_ai.data_preparation.executors.pipeline_executor import PipelineExecutor
7
7
  from mage_ai.data_preparation.models.pipeline import Pipeline
8
8
  from mage_ai.data_preparation.shared.utils import get_template_vars
9
+ from mage_ai.orchestration.db import safe_db_query
10
+ from mage_ai.orchestration.db.models.schedules import PipelineRun
9
11
  from mage_ai.services.k8s.config import K8sExecutorConfig
10
12
  from mage_ai.services.k8s.constants import DEFAULT_NAMESPACE
11
13
  from mage_ai.services.k8s.job_manager import JobManager as K8sJobManager
12
14
  from mage_ai.shared.hash import merge_dict
15
+ from mage_ai.shared.utils import clean_name
13
16
 
14
17
 
15
18
  class K8sPipelineExecutor(PipelineExecutor):
16
19
  def __init__(self, pipeline: Pipeline, execution_partition: str = None):
17
20
  super().__init__(pipeline, execution_partition=execution_partition)
18
- self.executor_config = self.pipeline.repo_config.k8s_executor_config or dict()
21
+ self.executor_config_dict = self.pipeline.repo_config.k8s_executor_config or dict()
19
22
  if self.pipeline.executor_config is not None:
20
- self.executor_config = merge_dict(self.executor_config, self.pipeline.executor_config)
21
- self.executor_config = K8sExecutorConfig.load(config=self.executor_config)
23
+ self.executor_config_dict = merge_dict(
24
+ self.executor_config_dict,
25
+ self.pipeline.executor_config,
26
+ )
27
+ self.executor_config = K8sExecutorConfig.load(config=self.executor_config_dict)
22
28
 
23
29
  def cancel(
24
30
  self,
@@ -63,10 +69,7 @@ class K8sPipelineExecutor(PipelineExecutor):
63
69
  ) -> K8sJobManager:
64
70
  if global_vars is None:
65
71
  global_vars = dict()
66
- if not self.executor_config.job_name_prefix:
67
- job_name_prefix = 'data-prep'
68
- else:
69
- job_name_prefix = self.executor_config.job_name_prefix
72
+ job_name_prefix = self._get_job_name_prefix(pipeline_run_id)
70
73
 
71
74
  if self.executor_config.namespace:
72
75
 
@@ -83,3 +86,23 @@ class K8sPipelineExecutor(PipelineExecutor):
83
86
  logging_tags=kwargs.get('tags', dict()),
84
87
  namespace=namespace,
85
88
  )
89
+
90
+ @safe_db_query
91
+ def _get_job_name_prefix(
92
+ self,
93
+ pipeline_run_id,
94
+ ):
95
+ if not self.executor_config.job_name_prefix:
96
+ job_name_prefix = 'data-prep'
97
+ else:
98
+ job_name_prefix = self.executor_config.job_name_prefix
99
+ if not pipeline_run_id:
100
+ return job_name_prefix
101
+
102
+ if '{trigger_name}' in job_name_prefix:
103
+ pipeline_run = PipelineRun.query.get(pipeline_run_id)
104
+ trigger = pipeline_run.pipeline_schedule
105
+ job_name_prefix = job_name_prefix.format(
106
+ trigger_name=clean_name(trigger.name).replace('_', '-'))
107
+
108
+ return job_name_prefix
@@ -84,7 +84,7 @@ class StreamingPipelineExecutor(PipelineExecutor):
84
84
  # 1. Support multiple sources and sinks
85
85
  # 2. Support flink pipeline
86
86
 
87
- tags = self.build_tags(**kwargs)
87
+ tags = self.build_tags(pipeline_run_id=pipeline_run_id, **kwargs)
88
88
  self.logging_tags = tags
89
89
  if build_block_output_stdout:
90
90
  stdout_logger = logging.getLogger('streaming_pipeline_executor')
@@ -19,9 +19,11 @@ from mage_ai.data_preparation.git.utils import (
19
19
  check_connection_async,
20
20
  create_ssh_keys,
21
21
  get_access_token,
22
+ get_oauth_access_token_for_user,
22
23
  get_provider_from_remote_url,
23
24
  poll_process_with_timeout,
24
25
  run_command,
26
+ validate_authentication_for_remote_url,
25
27
  )
26
28
  from mage_ai.data_preparation.preferences import get_preferences
27
29
  from mage_ai.data_preparation.sync import AuthType, GitConfig
@@ -79,8 +81,7 @@ class Git:
79
81
  if setup_repo:
80
82
  self.__setup_repo()
81
83
 
82
- if self.repo and self.git_config:
83
- self.__set_git_config()
84
+ self.__set_git_config()
84
85
 
85
86
  if self.remote_repo_link and self.repo:
86
87
  try:
@@ -162,6 +163,9 @@ class Git:
162
163
 
163
164
  git_config = GitConfig.load(config=config)
164
165
 
166
+ if auth_type is None:
167
+ auth_type = git_config.auth_type
168
+
165
169
  return Git(
166
170
  auth_type=auth_type,
167
171
  git_config=git_config,
@@ -182,8 +186,11 @@ class Git:
182
186
 
183
187
  return [branch.name for branch in self.repo.branches]
184
188
 
185
- async def check_connection(self) -> None:
186
- await check_connection_async(self.repo.git, self.origin.name)
189
+ async def check_connection(self, remote_url: str = None) -> None:
190
+ if remote_url:
191
+ await validate_authentication_for_remote_url(self.repo.git, remote_url)
192
+ else:
193
+ await check_connection_async(self.repo.git, self.origin.name)
187
194
 
188
195
  def _remote_command(func: Callable) -> None:
189
196
  """
@@ -224,19 +231,19 @@ class Git:
224
231
  elif self.auth_type == AuthType.HTTPS:
225
232
  token = self.get_access_token()
226
233
  url_original = list(self.origin.urls)[0]
234
+ remote_repo_link = self.remote_repo_link
227
235
  if self.git_config and self.remote_repo_link and token:
228
- self.remote_repo_link = build_authenticated_remote_url(
236
+ remote_repo_link = build_authenticated_remote_url(
229
237
  self.remote_repo_link,
230
238
  self.git_config.username,
231
239
  token,
232
240
  )
233
- self.origin.set_url(self.remote_repo_link)
241
+ self.origin.set_url(remote_repo_link)
234
242
  try:
235
- asyncio.run(self.check_connection())
243
+ asyncio.run(self.check_connection(remote_url=remote_repo_link))
236
244
  return func(self, *args, **kwargs)
237
245
  finally:
238
246
  self.origin.set_url(url_original)
239
- self.remote_repo_link = url_original
240
247
  return wrapper
241
248
 
242
249
  def add_remote(self, name: str, url: str) -> None:
@@ -432,6 +439,10 @@ class Git:
432
439
  self.repo.git.reset('--hard', f'{remote.name}/{branch}')
433
440
  self.__pip_install()
434
441
 
442
+ @_remote_command
443
+ def fetch(self) -> None:
444
+ self.origin.fetch()
445
+
435
446
  @_remote_command
436
447
  def push(self) -> None:
437
448
  self.repo.git.push(
@@ -564,7 +575,7 @@ class Git:
564
575
  if len(remote_refs) == 0 and user:
565
576
  from mage_ai.data_preparation.git import api
566
577
 
567
- access_token = api.get_access_token_for_user(user)
578
+ access_token = get_oauth_access_token_for_user(user)
568
579
  if access_token:
569
580
 
570
581
  if remote_exists:
@@ -685,15 +696,22 @@ class Git:
685
696
  elif remote:
686
697
  # For remote branches, switch to the local branch if it exists. Otherwise create a new
687
698
  # branch using the remote branch as the starting point.
688
- if branch.startswith(remote):
689
- branch = branch[len(remote) + 1:]
690
- if branch in self.repo.heads:
691
- self.repo.git.switch(branch)
692
- else:
693
- self.repo.git.switch('-c', branch, f'{remote}/{branch}')
699
+ self._switch_remote_branch(branch, remote)
694
700
  else:
695
701
  self.repo.git.switch('-c', branch)
696
702
 
703
+ @_remote_command
704
+ def _switch_remote_branch(self, branch: str, remote: str) -> None:
705
+ self.switch_remote_branch(branch, remote)
706
+
707
+ def switch_remote_branch(self, branch: str, remote: str) -> None:
708
+ if branch.startswith(remote):
709
+ branch = branch[len(remote) + 1:]
710
+ if branch in self.repo.heads:
711
+ self.repo.git.switch(branch)
712
+ else:
713
+ self.repo.git.switch('-c', branch, f'{remote}/{branch}')
714
+
697
715
  @_remote_command
698
716
  def clone(self, sync_submodules: bool = False) -> None:
699
717
  from git import Repo
@@ -729,13 +747,23 @@ class Git:
729
747
  shutil.rmtree(tmp_path)
730
748
 
731
749
  def __set_git_config(self):
732
- if self.git_config.username:
733
- self.repo.config_writer().set_value(
734
- 'user', 'name', self.git_config.username).release()
735
- if self.git_config.email:
736
- self.repo.config_writer().set_value(
737
- 'user', 'email', self.git_config.email).release()
738
- self.repo.config_writer('global').set_value(
750
+ from git.config import GitConfigParser
751
+ if self.git_config:
752
+ if self.git_config.username:
753
+ self.repo.config_writer().set_value(
754
+ 'user', 'name', self.git_config.username).release()
755
+ if self.git_config.email:
756
+ self.repo.config_writer().set_value(
757
+ 'user', 'email', self.git_config.email).release()
758
+
759
+ # This GitConfigParser is created in the same way that GitPython creates a
760
+ # global config parser. We create it this way to avoid needing to create a
761
+ # git.Repo object.
762
+ global_config = GitConfigParser(
763
+ os.path.normpath(os.path.expanduser("~/.gitconfig")),
764
+ read_only=False,
765
+ )
766
+ global_config.set_value(
739
767
  'safe', 'directory', Path(self.repo_path).as_posix()).release()
740
768
 
741
769
  def __pip_install(self) -> None:
@@ -3,9 +3,6 @@ import shutil
3
3
  import uuid
4
4
  from typing import Dict
5
5
 
6
- from git.remote import RemoteProgress
7
- from git.repo.base import Repo
8
-
9
6
  from mage_ai.authentication.oauth.constants import ProviderName, get_ghe_hostname
10
7
  from mage_ai.authentication.oauth.utils import access_tokens_for_client
11
8
  from mage_ai.data_preparation.git.clients.base import Client as GitClient
@@ -33,13 +30,51 @@ def get_access_token_for_user(user: User, provider: str = None) -> Oauth2AccessT
33
30
  return access_tokens[0]
34
31
 
35
32
 
33
+ def switch_branch(
34
+ remote_name: str,
35
+ remote_url: str,
36
+ branch_name: str,
37
+ token: str,
38
+ config_overwrite: Dict = None,
39
+ user: User = None,
40
+ ):
41
+ from mage_ai.data_preparation.git import Git
42
+ provider = get_provider_from_remote_url(remote_url)
43
+ username = get_username(token, user=user, provider=provider)
44
+
45
+ url = build_authenticated_remote_url(remote_url, username, token)
46
+ git_manager = Git.get_manager(user=user, config_overwrite=config_overwrite)
47
+
48
+ remote = git_manager.repo.remotes[remote_name]
49
+ url_original = list(remote.urls)[0]
50
+ remote.set_url(url)
51
+
52
+ try:
53
+ git_manager.switch_remote_branch(branch_name, remote_name)
54
+ except Exception as err:
55
+ raise err
56
+ finally:
57
+ try:
58
+ remote.set_url(url_original)
59
+ except Exception as err:
60
+ print('WARNING (mage_ai.data_preparation.git.api):')
61
+ print(err)
62
+
63
+
36
64
  def fetch(
37
65
  remote_name: str,
38
66
  remote_url: str,
39
67
  token: str,
40
68
  user: User = None,
41
69
  config_overwrite: Dict = None,
42
- ) -> RemoteProgress:
70
+ ):
71
+ """
72
+ Returns:
73
+ git.remote.RemoteProgress: Custom progress object that can be used to monitor the
74
+ fetch progress.
75
+ """
76
+ from git.remote import RemoteProgress
77
+
43
78
  from mage_ai.data_preparation.git import Git
44
79
 
45
80
  custom_progress = RemoteProgress()
@@ -74,7 +109,14 @@ def pull(
74
109
  token: str,
75
110
  user: User = None,
76
111
  config_overwrite: Dict = None,
77
- ) -> RemoteProgress:
112
+ ):
113
+ """
114
+ Returns:
115
+ git.remote.RemoteProgress: Custom progress object that can be used to monitor the
116
+ pull progress.
117
+ """
118
+ from git.remote import RemoteProgress
119
+
78
120
  from mage_ai.data_preparation.git import Git
79
121
 
80
122
  custom_progress = RemoteProgress()
@@ -110,7 +152,13 @@ def push_raw(
110
152
  token: str,
111
153
  user: User = None,
112
154
  **kwargs,
113
- ) -> RemoteProgress:
155
+ ):
156
+ """
157
+ Returns:
158
+ git.remote.RemoteProgress: Custom progress object that can be used to monitor the
159
+ push progress.
160
+ """
161
+ from git.remote import RemoteProgress
114
162
  custom_progress = RemoteProgress()
115
163
  provider = get_provider_from_remote_url(remote_url)
116
164
  username = get_username(token, user=user, provider=provider)
@@ -142,7 +190,12 @@ def push(
142
190
  token: str,
143
191
  user: User = None,
144
192
  config_overwrite: Dict = None,
145
- ) -> RemoteProgress:
193
+ ):
194
+ """
195
+ Returns:
196
+ git.remote.RemoteProgress: Custom progress object that can be used to monitor the
197
+ push progress.
198
+ """
146
199
  from mage_ai.data_preparation.git import Git
147
200
 
148
201
  git_manager = Git.get_manager(user=user, config_overwrite=config_overwrite)
@@ -213,6 +266,8 @@ def clone(
213
266
  tmp_path = f'{git_manager.repo_path}_{uuid.uuid4().hex}'
214
267
  os.mkdir(tmp_path)
215
268
  try:
269
+ from git.repo.base import Repo
270
+
216
271
  # Clone to a tmp folder first, then copy the folder to the actual repo path. Git
217
272
  # won't allow you to clone to a folder that is not empty.
218
273
  Repo.clone_from(
@@ -6,16 +6,20 @@ from typing import Callable
6
6
  from urllib.parse import urlparse, urlsplit, urlunsplit
7
7
 
8
8
  from mage_ai.authentication.oauth.constants import ProviderName, get_ghe_hostname
9
+ from mage_ai.authentication.oauth.utils import access_tokens_for_client
9
10
  from mage_ai.data_preparation.git.constants import (
10
11
  DEFAULT_KNOWN_HOSTS_FILE,
11
12
  DEFAULT_SSH_KEY_DIRECTORY,
12
13
  )
14
+ from mage_ai.data_preparation.repo_manager import get_project_uuid
13
15
  from mage_ai.data_preparation.shared.secrets import get_secret_value
14
16
  from mage_ai.data_preparation.sync import AuthType, GitConfig
15
- from mage_ai.settings import get_settings_value
17
+ from mage_ai.orchestration.db.models.oauth import Oauth2AccessToken, User
18
+ from mage_ai.settings import get_bool_value, get_settings_value
16
19
  from mage_ai.settings.keys import (
17
20
  BITBUCKET_HOST,
18
21
  GIT_ACCESS_TOKEN,
22
+ GIT_OVERWRITE_WITH_PROJECT_SETTINGS,
19
23
  GIT_SSH_PRIVATE_KEY,
20
24
  GIT_SSH_PUBLIC_KEY,
21
25
  GITLAB_HOST,
@@ -52,19 +56,23 @@ def get_provider_from_remote_url(remote_url: str) -> str:
52
56
  return ProviderName.GITHUB
53
57
 
54
58
 
55
- def create_ssh_keys(git_config: GitConfig, repo_path: str, overwrite: bool = False) -> str:
59
+ def create_ssh_keys(
60
+ git_config: GitConfig, repo_path: str, overwrite: bool = False
61
+ ) -> str:
56
62
  if not os.path.exists(DEFAULT_SSH_KEY_DIRECTORY):
57
63
  os.mkdir(DEFAULT_SSH_KEY_DIRECTORY, 0o700)
58
64
  pubk_secret_name = git_config.ssh_public_key_secret_name
65
+ overwrite_with_project_settings = get_bool_value(
66
+ get_settings_value(GIT_OVERWRITE_WITH_PROJECT_SETTINGS)
67
+ )
59
68
  if pubk_secret_name:
60
69
  public_key_file = os.path.join(
61
- DEFAULT_SSH_KEY_DIRECTORY,
62
- f'id_rsa_{pubk_secret_name}.pub'
70
+ DEFAULT_SSH_KEY_DIRECTORY, f'id_rsa_{pubk_secret_name}.pub'
63
71
  )
64
72
  if not os.path.exists(public_key_file) or overwrite:
65
73
  try:
66
74
  public_key = get_settings_value(GIT_SSH_PUBLIC_KEY)
67
- if not public_key:
75
+ if not public_key or overwrite_with_project_settings:
68
76
  public_key = get_secret_value(
69
77
  pubk_secret_name,
70
78
  repo_name=repo_path,
@@ -80,13 +88,12 @@ def create_ssh_keys(git_config: GitConfig, repo_path: str, overwrite: bool = Fal
80
88
  private_key_file = os.path.join(DEFAULT_SSH_KEY_DIRECTORY, 'id_rsa')
81
89
  if pk_secret_name:
82
90
  custom_private_key_file = os.path.join(
83
- DEFAULT_SSH_KEY_DIRECTORY,
84
- f'id_rsa_{pk_secret_name}'
91
+ DEFAULT_SSH_KEY_DIRECTORY, f'id_rsa_{pk_secret_name}'
85
92
  )
86
93
  if not os.path.exists(custom_private_key_file) or overwrite:
87
94
  try:
88
95
  private_key = get_settings_value(GIT_SSH_PRIVATE_KEY)
89
- if not private_key:
96
+ if not private_key or overwrite_with_project_settings:
90
97
  private_key = get_secret_value(
91
98
  pk_secret_name,
92
99
  repo_name=repo_path,
@@ -142,11 +149,16 @@ def add_host_to_known_hosts(remote_repo_link: str):
142
149
 
143
150
  def get_access_token(git_config, repo_path: str = None) -> str:
144
151
  token = get_settings_value(GIT_ACCESS_TOKEN)
145
- if not token and git_config and git_config.access_token_secret_name:
146
- token = get_secret_value(
152
+ overwrite_with_project_settings = get_bool_value(
153
+ get_settings_value(GIT_OVERWRITE_WITH_PROJECT_SETTINGS)
154
+ )
155
+ if git_config and git_config.access_token_secret_name:
156
+ token_from_secrets = get_secret_value(
147
157
  git_config.access_token_secret_name,
148
158
  repo_name=repo_path or get_repo_path(),
149
159
  )
160
+ if not token or overwrite_with_project_settings:
161
+ token = token_from_secrets
150
162
 
151
163
  return token
152
164
 
@@ -179,10 +191,7 @@ async def poll_process_with_timeout(
179
191
  if return_code is not None:
180
192
  out, err = proc.communicate()
181
193
  if return_code != 0:
182
- message = (
183
- err.decode('UTF-8') if err
184
- else error_message
185
- )
194
+ message = err.decode('UTF-8') if err else error_message
186
195
  raise ChildProcessError(message)
187
196
  else:
188
197
  return out.decode('UTF-8') if out else None
@@ -205,17 +214,16 @@ async def check_connection_async(git, remote_name: str) -> None:
205
214
  'Error connecting to remote, make sure your access token or SSH key is '
206
215
  'set up properly.'
207
216
  ),
217
+ timeout=5,
208
218
  )
209
219
 
210
220
 
211
221
  async def validate_authentication_for_remote_url(git, remote_url: str) -> None:
212
222
  proc = git.ls_remote(remote_url, as_process=True)
213
223
 
214
- asyncio.run(
215
- poll_process_with_timeout(
216
- proc,
217
- error_message='Error connecting to remote, make sure your access is valid.',
218
- )
224
+ await poll_process_with_timeout(
225
+ proc,
226
+ error_message='Error connecting to remote, make sure your access is valid.',
219
227
  )
220
228
 
221
229
 
@@ -258,14 +266,30 @@ def execute_on_remote_branch(func: Callable, branch) -> None:
258
266
  if hostname:
259
267
  await __add_host_to_known_hosts(remote_name)
260
268
  else:
261
- raise TimeoutError("""
269
+ raise TimeoutError(
270
+ """
262
271
  Connecting to remote timed out, make sure your SSH key is set up properly
263
272
  and your repository host is added as a known host. More information
264
273
  here: https://docs.mage.ai/developing-in-the-cloud/setting-up-git#5-add-github-com-to-known-hosts
265
- """)
274
+ """
275
+ )
266
276
  return await func(*args, **kwargs)
267
277
  else:
268
278
  await check_connection_async(git, remote_name)
269
279
  return await func(*args, **kwargs)
270
280
 
271
281
  return wrapper
282
+
283
+
284
+ def get_oauth_client_id(provider: str) -> str:
285
+ return f'{provider}_{get_project_uuid()}'
286
+
287
+
288
+ def get_oauth_access_token_for_user(
289
+ user: User, provider: str = None
290
+ ) -> Oauth2AccessToken:
291
+ if not provider:
292
+ provider = ProviderName.GHE if get_ghe_hostname() else ProviderName.GITHUB
293
+ access_tokens = access_tokens_for_client(get_oauth_client_id(provider), user=user)
294
+ if access_tokens:
295
+ return access_tokens[0]
@@ -1122,6 +1122,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1122
1122
  data_integration_runtime_settings: Dict = None,
1123
1123
  execution_partition_previous: str = None,
1124
1124
  metadata: Dict = None,
1125
+ override_outputs: bool = True,
1125
1126
  **kwargs,
1126
1127
  ) -> Dict:
1127
1128
  if logging_tags is None:
@@ -1213,7 +1214,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1213
1214
  DX_PRINTER.critical(
1214
1215
  block=self,
1215
1216
  execution_partition=execution_partition,
1216
- override_outputs=True,
1217
+ override_outputs=override_outputs,
1217
1218
  dynamic_block_uuid=dynamic_block_uuid,
1218
1219
  __uuid='store_variables',
1219
1220
  )
@@ -1221,7 +1222,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1221
1222
  self.store_variables(
1222
1223
  variable_mapping,
1223
1224
  execution_partition=execution_partition,
1224
- override_outputs=True,
1225
+ override_outputs=override_outputs,
1225
1226
  spark=self.__get_spark_session_from_global_vars(
1226
1227
  global_vars=global_vars,
1227
1228
  ),
@@ -1616,7 +1617,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1616
1617
 
1617
1618
  block_function = self._validate_execution(decorated_functions, input_vars)
1618
1619
  if block_function is not None:
1619
- if logger and 'logger' not in global_vars:
1620
+ if logger:
1620
1621
  global_vars['logger'] = logger
1621
1622
 
1622
1623
  track_spark = from_notebook and self.should_track_spark()
@@ -1780,6 +1781,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1780
1781
  global_vars=global_vars,
1781
1782
  metadata=metadata,
1782
1783
  upstream_block_uuids_override=upstream_block_uuids_override,
1784
+ current_block=self,
1783
1785
  )
1784
1786
 
1785
1787
  return variables
@@ -2386,8 +2388,17 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2386
2388
 
2387
2389
  def get_executor_type(self) -> str:
2388
2390
  if self.executor_type:
2389
- return Template(self.executor_type).render(**get_template_vars())
2390
- return self.executor_type
2391
+ block_executor_type = Template(self.executor_type).render(**get_template_vars())
2392
+ else:
2393
+ block_executor_type = None
2394
+ if not block_executor_type or block_executor_type == ExecutorType.LOCAL_PYTHON:
2395
+ # If block executor_type is not set, fall back to pipeline level executor_type
2396
+ if self.pipeline:
2397
+ pipeline_executor_type = self.pipeline.get_executor_type()
2398
+ else:
2399
+ pipeline_executor_type = None
2400
+ block_executor_type = pipeline_executor_type or block_executor_type
2401
+ return block_executor_type
2391
2402
 
2392
2403
  def get_pipelines_from_cache(self, block_cache: BlockCache = None) -> List[Dict]:
2393
2404
  if block_cache is None:
@@ -2994,6 +3005,8 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2994
3005
  global_vars: Dict = None,
2995
3006
  dynamic_block_index: int = None,
2996
3007
  ) -> Dict:
3008
+ from mage_ai.data_preparation.models.block.remote.models import RemoteBlock
3009
+
2997
3010
  """
2998
3011
  Enriches the provided global variables dictionary with additional context, Spark session,
2999
3012
  environment, configuration, and an empty context dictionary.
@@ -3040,6 +3053,12 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
3040
3053
  if dynamic_block_index is not None:
3041
3054
  global_vars['dynamic_block_index'] = dynamic_block_index
3042
3055
 
3056
+ # Remote blocks
3057
+ if global_vars.get('remote_blocks'):
3058
+ global_vars['remote_blocks'] = [RemoteBlock.load(
3059
+ **remote_block_dict,
3060
+ ).get_outputs() for remote_block_dict in global_vars['remote_blocks']]
3061
+
3043
3062
  self.global_vars = global_vars
3044
3063
 
3045
3064
  return global_vars
@@ -9,7 +9,10 @@ import pandas as pd
9
9
  from mage_ai.data_preparation.models.block.dynamic.variables import (
10
10
  get_outputs_for_dynamic_block,
11
11
  )
12
- from mage_ai.data_preparation.models.constants import DATAFRAME_ANALYSIS_MAX_COLUMNS
12
+ from mage_ai.data_preparation.models.constants import (
13
+ DATAFRAME_ANALYSIS_MAX_COLUMNS,
14
+ DATAFRAME_SAMPLE_COUNT_PREVIEW,
15
+ )
13
16
  from mage_ai.server.kernel_output_parser import DataType
14
17
  from mage_ai.shared.array import find
15
18
  from mage_ai.shared.custom_logger import DX_PRINTER
@@ -245,7 +248,9 @@ def transform_dataframe_for_display(dataframe: pd.DataFrame) -> Dict:
245
248
  data = dict(
246
249
  columns=columns_to_display,
247
250
  rows=json.loads(
248
- dataframe[columns_to_display].to_json(orient='split')
251
+ dataframe[columns_to_display][:DATAFRAME_SAMPLE_COUNT_PREVIEW].to_json(
252
+ orient='split',
253
+ )
249
254
  )['data'],
250
255
  index=list(dataframe.index),
251
256
  shape=[row_count, column_count],
@@ -253,7 +258,7 @@ def transform_dataframe_for_display(dataframe: pd.DataFrame) -> Dict:
253
258
  else:
254
259
  data = dict(
255
260
  columns=['col0'],
256
- rows=[[dataframe]],
261
+ rows=[[dataframe[:DATAFRAME_SAMPLE_COUNT_PREVIEW]]],
257
262
  index=[0],
258
263
  shape=[1, 1],
259
264
  )
@@ -413,7 +418,7 @@ def transform_output_for_display_dynamic_child(
413
418
  df = pd.concat([df, df_inner], axis=1)
414
419
 
415
420
  df = limit_output(df, sample_count)
416
- if 1 == len(set(df.columns)):
421
+ if isinstance(df, pd.DataFrame) and 1 == len(set(df.columns)):
417
422
  df.columns = [f'{col}_{idx}' for idx, col in enumerate(df.columns)]
418
423
 
419
424
  return transform_dataframe_for_display(df)
@@ -2,6 +2,7 @@ from logging import Logger
2
2
  from typing import Dict, List
3
3
 
4
4
  from mage_ai.data_preparation.models.block import Block
5
+ from mage_ai.data_preparation.models.block.remote.models import RemoteBlock
5
6
 
6
7
 
7
8
  class GlobalDataProductBlock(Block):
@@ -37,13 +38,35 @@ class GlobalDataProductBlock(Block):
37
38
  # Avoid circular dependency of Pipeline class
38
39
  from mage_ai.orchestration.triggers import global_data_product as trigger
39
40
 
40
- trigger.trigger_and_check_status(
41
- self.get_global_data_product(),
41
+ global_data_product = self.get_global_data_product()
42
+
43
+ pipeline_run = trigger.trigger_and_check_status(
44
+ global_data_product,
42
45
  block=self,
43
46
  from_notebook=from_notebook,
44
47
  logger=logger,
45
48
  logging_tags=logging_tags,
49
+ poll_interval=30,
50
+ remote_blocks=global_vars.get('remote_blocks'),
46
51
  variables=global_vars.get('variables') if global_vars else None,
47
52
  )
48
53
 
54
+ if pipeline_run and pipeline_run.pipeline:
55
+ pipeline = pipeline_run.pipeline
56
+
57
+ arr = []
58
+
59
+ for block in global_data_product.get_blocks():
60
+ if block and block.uuid:
61
+ arr.append(RemoteBlock.load(
62
+ block_uuid=block.uuid,
63
+ execution_partition=pipeline_run.execution_partition,
64
+ pipeline_uuid=pipeline.uuid,
65
+ repo_path=pipeline.repo_path,
66
+ ))
67
+
68
+ return [
69
+ dict(remote_blocks=arr),
70
+ ]
71
+
49
72
  return []