mage-ai 0.9.69__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 (624) 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/BackfillPolicy.py +1 -0
  6. mage_ai/api/policies/BlockOutputPolicy.py +40 -17
  7. mage_ai/api/policies/GlobalDataProductPolicy.py +91 -41
  8. mage_ai/api/policies/KernelPolicy.py +55 -32
  9. mage_ai/api/policies/KernelProcessPolicy.py +56 -0
  10. mage_ai/api/policies/OutputPolicy.py +73 -41
  11. mage_ai/api/policies/PipelinePolicy.py +206 -137
  12. mage_ai/api/policies/WorkspacePolicy.py +1 -0
  13. mage_ai/api/presenters/BackfillPresenter.py +1 -0
  14. mage_ai/api/presenters/BlockLayoutItemPresenter.py +9 -7
  15. mage_ai/api/presenters/BlockPresenter.py +1 -1
  16. mage_ai/api/presenters/GlobalDataProductPresenter.py +6 -1
  17. mage_ai/api/presenters/KernelPresenter.py +5 -26
  18. mage_ai/api/presenters/KernelProcessPresenter.py +28 -0
  19. mage_ai/api/presenters/PipelinePresenter.py +18 -5
  20. mage_ai/api/presenters/StatusPresenter.py +2 -0
  21. mage_ai/api/presenters/SyncPresenter.py +25 -0
  22. mage_ai/api/resources/AutocompleteItemResource.py +1 -1
  23. mage_ai/api/resources/BlockLayoutItemResource.py +90 -44
  24. mage_ai/api/resources/BlockOutputResource.py +42 -9
  25. mage_ai/api/resources/BlockResource.py +4 -3
  26. mage_ai/api/resources/BlockRunResource.py +27 -22
  27. mage_ai/api/resources/ClusterResource.py +4 -1
  28. mage_ai/api/resources/CustomTemplateResource.py +34 -14
  29. mage_ai/api/resources/DataProviderResource.py +1 -1
  30. mage_ai/api/resources/ExecutionStateResource.py +3 -1
  31. mage_ai/api/resources/FileContentResource.py +8 -2
  32. mage_ai/api/resources/FileResource.py +10 -4
  33. mage_ai/api/resources/FileVersionResource.py +3 -1
  34. mage_ai/api/resources/GitBranchResource.py +101 -31
  35. mage_ai/api/resources/GitCustomBranchResource.py +29 -1
  36. mage_ai/api/resources/GlobalDataProductResource.py +44 -7
  37. mage_ai/api/resources/GlobalHookResource.py +4 -1
  38. mage_ai/api/resources/IntegrationDestinationResource.py +6 -2
  39. mage_ai/api/resources/IntegrationSourceResource.py +8 -4
  40. mage_ai/api/resources/IntegrationSourceStreamResource.py +6 -2
  41. mage_ai/api/resources/KernelProcessResource.py +44 -0
  42. mage_ai/api/resources/KernelResource.py +25 -3
  43. mage_ai/api/resources/OauthResource.py +1 -1
  44. mage_ai/api/resources/OutputResource.py +33 -11
  45. mage_ai/api/resources/PageBlockLayoutResource.py +34 -23
  46. mage_ai/api/resources/PipelineInteractionResource.py +31 -15
  47. mage_ai/api/resources/PipelineResource.py +258 -125
  48. mage_ai/api/resources/PipelineRunResource.py +52 -7
  49. mage_ai/api/resources/PipelineScheduleResource.py +11 -2
  50. mage_ai/api/resources/PipelineTriggerResource.py +6 -1
  51. mage_ai/api/resources/ProjectResource.py +18 -7
  52. mage_ai/api/resources/PullRequestResource.py +6 -4
  53. mage_ai/api/resources/SecretResource.py +1 -1
  54. mage_ai/api/resources/SeedResource.py +8 -1
  55. mage_ai/api/resources/StatusResource.py +21 -6
  56. mage_ai/api/resources/SyncResource.py +6 -8
  57. mage_ai/api/resources/VariableResource.py +46 -26
  58. mage_ai/api/resources/VersionControlProjectResource.py +9 -2
  59. mage_ai/api/resources/WidgetResource.py +1 -1
  60. mage_ai/api/resources/WorkspaceResource.py +6 -5
  61. mage_ai/api/views.py +47 -40
  62. mage_ai/authentication/permissions/seed.py +16 -2
  63. mage_ai/authentication/providers/oidc.py +21 -1
  64. mage_ai/autocomplete/utils.py +13 -9
  65. mage_ai/cache/base.py +1 -1
  66. mage_ai/cache/block.py +18 -12
  67. mage_ai/cache/block_action_object/__init__.py +33 -5
  68. mage_ai/cache/file.py +22 -19
  69. mage_ai/cache/pipeline.py +18 -12
  70. mage_ai/cli/main.py +1 -0
  71. mage_ai/cluster_manager/aws/emr_cluster_manager.py +9 -5
  72. mage_ai/cluster_manager/config.py +2 -2
  73. mage_ai/cluster_manager/kubernetes/workload_manager.py +52 -1
  74. mage_ai/cluster_manager/manage.py +1 -1
  75. mage_ai/cluster_manager/workspace/base.py +7 -1
  76. mage_ai/cluster_manager/workspace/kubernetes.py +22 -1
  77. mage_ai/command_center/applications/factory.py +10 -7
  78. mage_ai/command_center/applications/utils.py +2 -2
  79. mage_ai/command_center/files/factory.py +17 -15
  80. mage_ai/command_center/presenters/text.py +1 -1
  81. mage_ai/command_center/utils.py +25 -13
  82. mage_ai/data/__init__.py +0 -0
  83. mage_ai/data/constants.py +45 -0
  84. mage_ai/data/models/__init__.py +0 -0
  85. mage_ai/data/models/base.py +119 -0
  86. mage_ai/data/models/constants.py +1 -0
  87. mage_ai/data/models/generator.py +115 -0
  88. mage_ai/data/models/manager.py +168 -0
  89. mage_ai/data/models/pyarrow/__init__.py +0 -0
  90. mage_ai/data/models/pyarrow/record_batch.py +55 -0
  91. mage_ai/data/models/pyarrow/shared.py +21 -0
  92. mage_ai/data/models/pyarrow/table.py +8 -0
  93. mage_ai/data/models/reader.py +103 -0
  94. mage_ai/data/models/utils.py +59 -0
  95. mage_ai/data/models/writer.py +91 -0
  96. mage_ai/data/tabular/__init__.py +0 -0
  97. mage_ai/data/tabular/constants.py +23 -0
  98. mage_ai/data/tabular/mocks.py +19 -0
  99. mage_ai/data/tabular/models.py +126 -0
  100. mage_ai/data/tabular/reader.py +602 -0
  101. mage_ai/data/tabular/utils.py +102 -0
  102. mage_ai/data/tabular/writer.py +266 -0
  103. mage_ai/data/variables/__init__.py +0 -0
  104. mage_ai/data/variables/wrapper.py +54 -0
  105. mage_ai/data_cleaner/analysis/charts.py +61 -39
  106. mage_ai/data_cleaner/column_types/column_type_detector.py +53 -31
  107. mage_ai/data_cleaner/estimators/encoders.py +5 -2
  108. mage_ai/data_integrations/utils/scheduler.py +16 -11
  109. mage_ai/data_preparation/decorators.py +1 -0
  110. mage_ai/data_preparation/executors/block_executor.py +237 -155
  111. mage_ai/data_preparation/executors/k8s_block_executor.py +30 -7
  112. mage_ai/data_preparation/executors/k8s_pipeline_executor.py +30 -7
  113. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +2 -2
  114. mage_ai/data_preparation/git/__init__.py +77 -29
  115. mage_ai/data_preparation/git/api.py +69 -8
  116. mage_ai/data_preparation/git/utils.py +64 -34
  117. mage_ai/data_preparation/logging/logger_manager.py +4 -3
  118. mage_ai/data_preparation/models/block/__init__.py +1562 -879
  119. mage_ai/data_preparation/models/block/data_integration/mixins.py +4 -3
  120. mage_ai/data_preparation/models/block/dynamic/__init__.py +17 -6
  121. mage_ai/data_preparation/models/block/dynamic/child.py +41 -102
  122. mage_ai/data_preparation/models/block/dynamic/constants.py +1 -0
  123. mage_ai/data_preparation/models/block/dynamic/counter.py +296 -0
  124. mage_ai/data_preparation/models/block/dynamic/data.py +16 -0
  125. mage_ai/data_preparation/models/block/dynamic/factory.py +163 -0
  126. mage_ai/data_preparation/models/block/dynamic/models.py +19 -0
  127. mage_ai/data_preparation/models/block/dynamic/shared.py +92 -0
  128. mage_ai/data_preparation/models/block/dynamic/utils.py +295 -167
  129. mage_ai/data_preparation/models/block/dynamic/variables.py +384 -144
  130. mage_ai/data_preparation/models/block/dynamic/wrappers.py +77 -0
  131. mage_ai/data_preparation/models/block/extension/utils.py +10 -1
  132. mage_ai/data_preparation/models/block/global_data_product/__init__.py +35 -3
  133. mage_ai/data_preparation/models/block/integration/__init__.py +6 -2
  134. mage_ai/data_preparation/models/block/outputs.py +722 -0
  135. mage_ai/data_preparation/models/block/platform/mixins.py +7 -8
  136. mage_ai/data_preparation/models/block/r/__init__.py +56 -38
  137. mage_ai/data_preparation/models/block/remote/__init__.py +0 -0
  138. mage_ai/data_preparation/models/block/remote/models.py +58 -0
  139. mage_ai/data_preparation/models/block/settings/__init__.py +0 -0
  140. mage_ai/data_preparation/models/block/settings/dynamic/__init__.py +0 -0
  141. mage_ai/data_preparation/models/block/settings/dynamic/constants.py +7 -0
  142. mage_ai/data_preparation/models/block/settings/dynamic/mixins.py +118 -0
  143. mage_ai/data_preparation/models/block/settings/dynamic/models.py +31 -0
  144. mage_ai/data_preparation/models/block/settings/global_data_products/__init__.py +0 -0
  145. mage_ai/data_preparation/models/block/settings/global_data_products/mixins.py +20 -0
  146. mage_ai/data_preparation/models/block/settings/global_data_products/models.py +46 -0
  147. mage_ai/data_preparation/models/block/settings/variables/__init__.py +0 -0
  148. mage_ai/data_preparation/models/block/settings/variables/mixins.py +74 -0
  149. mage_ai/data_preparation/models/block/settings/variables/models.py +49 -0
  150. mage_ai/data_preparation/models/block/spark/mixins.py +2 -1
  151. mage_ai/data_preparation/models/block/sql/__init__.py +30 -5
  152. mage_ai/data_preparation/models/block/sql/utils/shared.py +21 -3
  153. mage_ai/data_preparation/models/block/utils.py +164 -69
  154. mage_ai/data_preparation/models/constants.py +21 -14
  155. mage_ai/data_preparation/models/custom_templates/custom_block_template.py +18 -13
  156. mage_ai/data_preparation/models/custom_templates/custom_pipeline_template.py +33 -16
  157. mage_ai/data_preparation/models/custom_templates/utils.py +1 -1
  158. mage_ai/data_preparation/models/file.py +41 -28
  159. mage_ai/data_preparation/models/global_data_product/__init__.py +100 -58
  160. mage_ai/data_preparation/models/global_hooks/models.py +1 -0
  161. mage_ai/data_preparation/models/interfaces.py +29 -0
  162. mage_ai/data_preparation/models/pipeline.py +374 -185
  163. mage_ai/data_preparation/models/pipelines/integration_pipeline.py +1 -2
  164. mage_ai/data_preparation/models/pipelines/seed.py +1 -1
  165. mage_ai/data_preparation/models/project/__init__.py +66 -18
  166. mage_ai/data_preparation/models/project/constants.py +2 -0
  167. mage_ai/data_preparation/models/triggers/__init__.py +124 -26
  168. mage_ai/data_preparation/models/utils.py +467 -17
  169. mage_ai/data_preparation/models/variable.py +1028 -137
  170. mage_ai/data_preparation/models/variables/__init__.py +0 -0
  171. mage_ai/data_preparation/models/variables/cache.py +149 -0
  172. mage_ai/data_preparation/models/variables/constants.py +72 -0
  173. mage_ai/data_preparation/models/variables/summarizer.py +336 -0
  174. mage_ai/data_preparation/models/variables/utils.py +77 -0
  175. mage_ai/data_preparation/models/widget/__init__.py +63 -41
  176. mage_ai/data_preparation/models/widget/charts.py +40 -27
  177. mage_ai/data_preparation/models/widget/constants.py +2 -0
  178. mage_ai/data_preparation/models/widget/utils.py +3 -3
  179. mage_ai/data_preparation/preferences.py +3 -3
  180. mage_ai/data_preparation/repo_manager.py +55 -21
  181. mage_ai/data_preparation/storage/base_storage.py +2 -2
  182. mage_ai/data_preparation/storage/gcs_storage.py +7 -4
  183. mage_ai/data_preparation/storage/local_storage.py +18 -9
  184. mage_ai/data_preparation/storage/s3_storage.py +5 -2
  185. mage_ai/data_preparation/templates/data_exporters/streaming/oracledb.yaml +8 -0
  186. mage_ai/data_preparation/variable_manager.py +281 -76
  187. mage_ai/io/base.py +3 -2
  188. mage_ai/io/bigquery.py +1 -0
  189. mage_ai/io/redshift.py +7 -5
  190. mage_ai/kernels/__init__.py +0 -0
  191. mage_ai/kernels/models.py +188 -0
  192. mage_ai/kernels/utils.py +169 -0
  193. mage_ai/orchestration/concurrency.py +6 -2
  194. mage_ai/orchestration/db/__init__.py +1 -0
  195. mage_ai/orchestration/db/migrations/versions/0227396a216c_add_userproject_table.py +38 -0
  196. mage_ai/orchestration/db/migrations/versions/42a14d6143f1_update_token_column_type.py +54 -0
  197. mage_ai/orchestration/db/models/dynamic/__init__.py +0 -0
  198. mage_ai/orchestration/db/models/dynamic/controller.py +67 -0
  199. mage_ai/orchestration/db/models/oauth.py +12 -18
  200. mage_ai/orchestration/db/models/projects.py +10 -0
  201. mage_ai/orchestration/db/models/schedules.py +225 -187
  202. mage_ai/orchestration/db/models/schedules_project_platform.py +18 -12
  203. mage_ai/orchestration/db/models/utils.py +46 -5
  204. mage_ai/orchestration/metrics/pipeline_run.py +8 -9
  205. mage_ai/orchestration/notification/sender.py +38 -15
  206. mage_ai/orchestration/pipeline_scheduler_original.py +64 -33
  207. mage_ai/orchestration/pipeline_scheduler_project_platform.py +1 -1
  208. mage_ai/orchestration/run_status_checker.py +11 -4
  209. mage_ai/orchestration/triggers/api.py +41 -2
  210. mage_ai/orchestration/triggers/global_data_product.py +9 -4
  211. mage_ai/orchestration/triggers/utils.py +10 -1
  212. mage_ai/orchestration/utils/resources.py +3 -0
  213. mage_ai/presenters/charts/data_sources/base.py +4 -2
  214. mage_ai/presenters/charts/data_sources/block.py +15 -9
  215. mage_ai/presenters/charts/data_sources/chart_code.py +8 -5
  216. mage_ai/presenters/charts/data_sources/constants.py +1 -0
  217. mage_ai/presenters/charts/data_sources/system_metrics.py +22 -0
  218. mage_ai/presenters/interactions/models.py +11 -7
  219. mage_ai/presenters/pages/loaders/pipelines.py +5 -3
  220. mage_ai/presenters/pages/models/page_components/pipeline_schedules.py +3 -1
  221. mage_ai/presenters/utils.py +2 -0
  222. mage_ai/server/api/blocks.py +2 -1
  223. mage_ai/server/api/downloads.py +9 -2
  224. mage_ai/server/api/runs.py +151 -0
  225. mage_ai/server/api/triggers.py +3 -1
  226. mage_ai/server/constants.py +1 -1
  227. mage_ai/server/frontend_dist/404.html +8 -8
  228. mage_ai/server/frontend_dist/_next/static/UZLabyPgcxtZvp0O0EUUS/_buildManifest.js +1 -0
  229. mage_ai/server/frontend_dist/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
  230. mage_ai/server/frontend_dist/_next/static/chunks/1557-25a7d985d5564fd3.js +1 -0
  231. mage_ai/server/frontend_dist/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
  232. mage_ai/server/frontend_dist/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
  233. mage_ai/server/frontend_dist/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
  234. mage_ai/server/frontend_dist/_next/static/chunks/{3548-fa0792ddb88f4646.js → 3548-9d26185b3fb663b1.js} +1 -1
  235. mage_ai/server/frontend_dist/_next/static/chunks/{3763-61b542dafdbf5754.js → 3763-40780c6d1e4b261d.js} +1 -1
  236. mage_ai/server/frontend_dist/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
  237. mage_ai/server/frontend_dist/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
  238. mage_ai/server/frontend_dist/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
  239. mage_ai/server/frontend_dist/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
  240. mage_ai/server/frontend_dist/_next/static/chunks/5699-176f445e1313f001.js +1 -0
  241. mage_ai/server/frontend_dist/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
  242. mage_ai/server/frontend_dist/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
  243. mage_ai/server/frontend_dist/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
  244. mage_ai/server/frontend_dist/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
  245. mage_ai/server/frontend_dist/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
  246. mage_ai/server/frontend_dist/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
  247. mage_ai/server/frontend_dist/_next/static/chunks/{main-77fe248a6fbd12d8.js → main-b99d4e30a88d9dc7.js} +1 -1
  248. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-9fe2d9d07c94e968.js +1 -0
  249. mage_ai/server/frontend_dist/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
  250. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
  251. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
  252. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
  253. mage_ai/server/frontend_dist/_next/static/chunks/pages/{overview-597b74828bf105db.js → overview-9f1ac4ec003884f3.js} +1 -1
  254. 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
  255. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7e737f6fc7e83e9b.js +1 -0
  256. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
  257. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
  258. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
  259. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
  260. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
  261. 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
  262. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
  263. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
  264. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
  265. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-1bdfda8edc9cf4a8.js → triggers-4612d15a65c35912.js} +1 -1
  266. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
  267. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js +1 -0
  268. 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
  269. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
  270. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
  271. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
  272. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
  273. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
  274. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
  275. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
  276. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
  277. mage_ai/server/frontend_dist/_next/static/chunks/pages/{triggers-9cba3211434a8966.js → triggers-a599c6ac89be8c8d.js} +1 -1
  278. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
  279. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-d079359c241db804.js → webpack-ac7fdc472bedf682.js} +1 -1
  280. mage_ai/server/frontend_dist/block-layout.html +3 -3
  281. mage_ai/server/frontend_dist/compute.html +6 -6
  282. mage_ai/server/frontend_dist/files.html +6 -6
  283. mage_ai/server/frontend_dist/global-data-products/[...slug].html +6 -6
  284. mage_ai/server/frontend_dist/global-data-products.html +6 -6
  285. mage_ai/server/frontend_dist/global-hooks/[...slug].html +6 -6
  286. mage_ai/server/frontend_dist/global-hooks.html +6 -6
  287. mage_ai/server/frontend_dist/index.html +3 -3
  288. mage_ai/server/frontend_dist/manage/files.html +6 -6
  289. mage_ai/server/frontend_dist/manage/settings.html +6 -6
  290. mage_ai/server/frontend_dist/manage/users/[user].html +6 -6
  291. mage_ai/server/frontend_dist/manage/users/new.html +6 -6
  292. mage_ai/server/frontend_dist/manage/users.html +6 -6
  293. mage_ai/server/frontend_dist/manage.html +6 -6
  294. mage_ai/server/frontend_dist/oauth.html +5 -5
  295. mage_ai/server/frontend_dist/overview.html +6 -6
  296. mage_ai/server/frontend_dist/pipeline-runs.html +6 -6
  297. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  298. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +6 -6
  299. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +6 -6
  300. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +3 -3
  301. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +6 -6
  302. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  303. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  304. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +6 -6
  305. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +6 -6
  306. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +6 -6
  307. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +6 -6
  308. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +6 -6
  309. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  310. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +6 -6
  311. mage_ai/server/frontend_dist/pipelines/[pipeline].html +3 -3
  312. mage_ai/server/frontend_dist/pipelines.html +6 -6
  313. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +6 -6
  314. mage_ai/server/frontend_dist/platform/global-hooks.html +6 -6
  315. mage_ai/server/frontend_dist/settings/account/profile.html +6 -6
  316. mage_ai/server/frontend_dist/settings/platform/preferences.html +6 -6
  317. mage_ai/server/frontend_dist/settings/platform/settings.html +6 -6
  318. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +6 -6
  319. mage_ai/server/frontend_dist/settings/workspace/permissions.html +6 -6
  320. mage_ai/server/frontend_dist/settings/workspace/preferences.html +6 -6
  321. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +6 -6
  322. mage_ai/server/frontend_dist/settings/workspace/roles.html +6 -6
  323. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +6 -6
  324. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +6 -6
  325. mage_ai/server/frontend_dist/settings/workspace/users.html +6 -6
  326. mage_ai/server/frontend_dist/settings.html +3 -3
  327. mage_ai/server/frontend_dist/sign-in.html +15 -15
  328. mage_ai/server/frontend_dist/templates/[...slug].html +6 -6
  329. mage_ai/server/frontend_dist/templates.html +6 -6
  330. mage_ai/server/frontend_dist/terminal.html +6 -6
  331. mage_ai/server/frontend_dist/test.html +3 -3
  332. mage_ai/server/frontend_dist/triggers.html +6 -6
  333. mage_ai/server/frontend_dist/version-control.html +6 -6
  334. mage_ai/server/frontend_dist_base_path_template/404.html +8 -8
  335. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
  336. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-25a7d985d5564fd3.js +1 -0
  337. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
  338. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
  339. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
  340. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3548-fa0792ddb88f4646.js → 3548-9d26185b3fb663b1.js} +1 -1
  341. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3763-61b542dafdbf5754.js → 3763-40780c6d1e4b261d.js} +1 -1
  342. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
  343. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
  344. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
  345. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
  346. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-176f445e1313f001.js +1 -0
  347. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
  348. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
  349. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
  350. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
  351. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
  352. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
  353. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{main-70b78159c2bb3fe1.js → main-384298e9133cec76.js} +1 -1
  354. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-13a578bce3b7f30c.js +1 -0
  355. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
  356. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
  357. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
  358. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
  359. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{overview-597b74828bf105db.js → overview-9f1ac4ec003884f3.js} +1 -1
  360. 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
  361. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7e737f6fc7e83e9b.js +1 -0
  362. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
  363. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
  364. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
  365. 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
  366. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
  367. 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
  368. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
  369. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
  370. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
  371. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-1bdfda8edc9cf4a8.js → triggers-4612d15a65c35912.js} +1 -1
  372. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
  373. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js +1 -0
  374. 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
  375. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
  376. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
  377. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
  378. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
  379. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
  380. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
  381. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
  382. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
  383. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{triggers-9cba3211434a8966.js → triggers-a599c6ac89be8c8d.js} +1 -1
  384. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
  385. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-68c003fb6a175cd7.js → webpack-481689d9989710cd.js} +1 -1
  386. mage_ai/server/frontend_dist_base_path_template/_next/static/kcptwoOU-JJJg6Vwpkfmx/_buildManifest.js +1 -0
  387. mage_ai/server/frontend_dist_base_path_template/block-layout.html +3 -3
  388. mage_ai/server/frontend_dist_base_path_template/compute.html +6 -6
  389. mage_ai/server/frontend_dist_base_path_template/files.html +6 -6
  390. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +6 -6
  391. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +6 -6
  392. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +6 -6
  393. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +6 -6
  394. mage_ai/server/frontend_dist_base_path_template/index.html +3 -3
  395. mage_ai/server/frontend_dist_base_path_template/manage/files.html +6 -6
  396. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +6 -6
  397. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +6 -6
  398. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +6 -6
  399. mage_ai/server/frontend_dist_base_path_template/manage/users.html +6 -6
  400. mage_ai/server/frontend_dist_base_path_template/manage.html +6 -6
  401. mage_ai/server/frontend_dist_base_path_template/oauth.html +5 -5
  402. mage_ai/server/frontend_dist_base_path_template/overview.html +6 -6
  403. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +6 -6
  404. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  405. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +6 -6
  406. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +6 -6
  407. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +3 -3
  408. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +6 -6
  409. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  410. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  411. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +6 -6
  412. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +6 -6
  413. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +6 -6
  414. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +6 -6
  415. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +6 -6
  416. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  417. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +6 -6
  418. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +3 -3
  419. mage_ai/server/frontend_dist_base_path_template/pipelines.html +6 -6
  420. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +6 -6
  421. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +6 -6
  422. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +6 -6
  423. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +6 -6
  424. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +6 -6
  425. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +6 -6
  426. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +6 -6
  427. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +6 -6
  428. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +6 -6
  429. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +6 -6
  430. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +6 -6
  431. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +6 -6
  432. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +6 -6
  433. mage_ai/server/frontend_dist_base_path_template/settings.html +3 -3
  434. mage_ai/server/frontend_dist_base_path_template/sign-in.html +15 -15
  435. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +6 -6
  436. mage_ai/server/frontend_dist_base_path_template/templates.html +6 -6
  437. mage_ai/server/frontend_dist_base_path_template/terminal.html +6 -6
  438. mage_ai/server/frontend_dist_base_path_template/test.html +3 -3
  439. mage_ai/server/frontend_dist_base_path_template/triggers.html +6 -6
  440. mage_ai/server/frontend_dist_base_path_template/version-control.html +6 -6
  441. mage_ai/server/kernel_output_parser.py +4 -1
  442. mage_ai/server/scheduler_manager.py +12 -1
  443. mage_ai/server/server.py +69 -42
  444. mage_ai/server/utils/custom_output.py +284 -0
  445. mage_ai/server/utils/execute_custom_code.py +245 -0
  446. mage_ai/server/utils/output_display.py +123 -289
  447. mage_ai/server/websocket_server.py +116 -69
  448. mage_ai/services/aws/ecs/ecs.py +1 -0
  449. mage_ai/services/k8s/config.py +27 -4
  450. mage_ai/services/k8s/job_manager.py +6 -1
  451. mage_ai/services/k8s/utils.py +97 -0
  452. mage_ai/services/ssh/aws/emr/utils.py +8 -8
  453. mage_ai/settings/keys/auth.py +1 -0
  454. mage_ai/settings/platform/__init__.py +159 -38
  455. mage_ai/settings/platform/constants.py +5 -0
  456. mage_ai/settings/platform/utils.py +53 -10
  457. mage_ai/settings/repo.py +26 -12
  458. mage_ai/settings/server.py +128 -37
  459. mage_ai/shared/array.py +24 -1
  460. mage_ai/shared/complex.py +45 -0
  461. mage_ai/shared/config.py +2 -1
  462. mage_ai/shared/custom_logger.py +11 -0
  463. mage_ai/shared/dates.py +10 -6
  464. mage_ai/shared/files.py +63 -8
  465. mage_ai/shared/hash.py +33 -9
  466. mage_ai/shared/io.py +9 -5
  467. mage_ai/shared/models.py +82 -24
  468. mage_ai/shared/outputs.py +87 -0
  469. mage_ai/shared/parsers.py +144 -13
  470. mage_ai/shared/path_fixer.py +11 -7
  471. mage_ai/shared/singletons/__init__.py +0 -0
  472. mage_ai/shared/singletons/base.py +47 -0
  473. mage_ai/shared/singletons/memory.py +38 -0
  474. mage_ai/shared/strings.py +34 -1
  475. mage_ai/shared/yaml.py +24 -0
  476. mage_ai/streaming/sinks/oracledb.py +57 -0
  477. mage_ai/streaming/sinks/sink_factory.py +4 -0
  478. mage_ai/system/__init__.py +0 -0
  479. mage_ai/system/constants.py +14 -0
  480. mage_ai/system/memory/__init__.py +0 -0
  481. mage_ai/system/memory/constants.py +1 -0
  482. mage_ai/system/memory/manager.py +174 -0
  483. mage_ai/system/memory/presenters.py +158 -0
  484. mage_ai/system/memory/process.py +216 -0
  485. mage_ai/system/memory/samples.py +13 -0
  486. mage_ai/system/memory/utils.py +656 -0
  487. mage_ai/system/memory/wrappers.py +177 -0
  488. mage_ai/system/models.py +58 -0
  489. mage_ai/system/storage/__init__.py +0 -0
  490. mage_ai/system/storage/utils.py +29 -0
  491. mage_ai/tests/api/endpoints/mixins.py +2 -2
  492. mage_ai/tests/api/endpoints/test_blocks.py +2 -1
  493. mage_ai/tests/api/endpoints/test_custom_designs.py +4 -4
  494. mage_ai/tests/api/endpoints/test_pipeline_runs.py +2 -2
  495. mage_ai/tests/api/endpoints/test_projects.py +2 -1
  496. mage_ai/tests/api/operations/base/mixins.py +1 -1
  497. mage_ai/tests/api/operations/base/test_base.py +27 -27
  498. mage_ai/tests/api/operations/base/test_base_with_user_authentication.py +27 -27
  499. mage_ai/tests/api/operations/base/test_base_with_user_permissions.py +23 -23
  500. mage_ai/tests/api/operations/test_syncs.py +6 -4
  501. mage_ai/tests/api/resources/test_pipeline_resource.py +11 -4
  502. mage_ai/tests/authentication/oauth/test_utils.py +1 -1
  503. mage_ai/tests/authentication/providers/test_oidc.py +59 -0
  504. mage_ai/tests/base_test.py +2 -2
  505. mage_ai/tests/data/__init__.py +0 -0
  506. mage_ai/tests/data/models/__init__.py +0 -0
  507. mage_ai/tests/data_preparation/executors/test_block_executor.py +23 -16
  508. mage_ai/tests/data_preparation/git/test_git.py +4 -1
  509. mage_ai/tests/data_preparation/models/block/dynamic/test_combos.py +305 -0
  510. mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +212 -0
  511. mage_ai/tests/data_preparation/models/block/dynamic/test_factory.py +360 -0
  512. mage_ai/tests/data_preparation/models/block/dynamic/test_variables.py +332 -0
  513. mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +2 -2
  514. mage_ai/tests/data_preparation/models/block/platform/test_mixins.py +1 -1
  515. mage_ai/tests/data_preparation/models/block/sql/utils/test_shared.py +26 -1
  516. mage_ai/tests/data_preparation/models/block/test_global_data_product.py +5 -2
  517. mage_ai/tests/data_preparation/models/custom_templates/test_utils.py +5 -4
  518. mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +3 -0
  519. mage_ai/tests/data_preparation/models/global_hooks/test_predicates.py +9 -3
  520. mage_ai/tests/data_preparation/models/test_block.py +115 -120
  521. mage_ai/tests/data_preparation/models/test_blocks_helper.py +114 -0
  522. mage_ai/tests/data_preparation/models/test_global_data_product.py +41 -24
  523. mage_ai/tests/data_preparation/models/test_pipeline.py +9 -6
  524. mage_ai/tests/data_preparation/models/test_project.py +4 -1
  525. mage_ai/tests/data_preparation/models/test_utils.py +80 -0
  526. mage_ai/tests/data_preparation/models/test_variable.py +242 -69
  527. mage_ai/tests/data_preparation/models/variables/__init__.py +0 -0
  528. mage_ai/tests/data_preparation/models/variables/test_summarizer.py +481 -0
  529. mage_ai/tests/data_preparation/storage/shared/__init__.py +0 -0
  530. mage_ai/tests/data_preparation/test_repo_manager.py +6 -7
  531. mage_ai/tests/data_preparation/test_variable_manager.py +57 -48
  532. mage_ai/tests/factory.py +64 -43
  533. mage_ai/tests/orchestration/db/models/test_schedules.py +3 -3
  534. mage_ai/tests/orchestration/db/models/test_schedules_dynamic_blocks.py +279 -0
  535. mage_ai/tests/orchestration/test_pipeline_scheduler.py +1 -0
  536. mage_ai/tests/orchestration/triggers/test_global_data_product.py +141 -138
  537. mage_ai/tests/orchestration/triggers/test_utils.py +3 -2
  538. mage_ai/tests/server/test_server.py +19 -0
  539. mage_ai/tests/services/k8s/test_job_manager.py +27 -6
  540. mage_ai/tests/streaming/sinks/test_oracledb.py +38 -0
  541. mage_ai/tests/test_shared.py +61 -0
  542. mage_ai/usage_statistics/logger.py +7 -2
  543. mage_ai/utils/code.py +33 -19
  544. mage_ai/version_control/branch/utils.py +2 -1
  545. mage_ai/version_control/models.py +3 -2
  546. {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/METADATA +6 -3
  547. {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/RECORD +555 -454
  548. mage_ai/data_preparation/models/global_data_product/constants.py +0 -6
  549. mage_ai/server/frontend_dist/_next/static/_krrrgup_C-dPOpX36S8I/_buildManifest.js +0 -1
  550. mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +0 -1
  551. mage_ai/server/frontend_dist/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
  552. mage_ai/server/frontend_dist/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
  553. mage_ai/server/frontend_dist/_next/static/chunks/4783-422429203610c318.js +0 -1
  554. mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
  555. mage_ai/server/frontend_dist/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
  556. mage_ai/server/frontend_dist/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
  557. mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
  558. mage_ai/server/frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
  559. mage_ai/server/frontend_dist/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
  560. mage_ai/server/frontend_dist/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
  561. mage_ai/server/frontend_dist/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
  562. mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
  563. mage_ai/server/frontend_dist/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
  564. mage_ai/server/frontend_dist/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
  565. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +0 -1
  566. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
  567. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
  568. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
  569. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
  570. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
  571. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
  572. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +0 -1
  573. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
  574. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
  575. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
  576. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
  577. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +0 -1
  578. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +0 -1
  579. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
  580. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js +0 -1
  581. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
  582. mage_ai/server/frontend_dist_base_path_template/_next/static/KLL5mirre9d7_ZeEpaw3s/_buildManifest.js +0 -1
  583. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +0 -1
  584. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
  585. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
  586. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4783-422429203610c318.js +0 -1
  587. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
  588. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
  589. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
  590. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
  591. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
  592. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
  593. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
  594. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
  595. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
  596. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
  597. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
  598. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +0 -1
  599. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
  600. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
  601. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
  602. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
  603. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
  604. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
  605. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +0 -1
  606. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
  607. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
  608. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
  609. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
  610. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +0 -1
  611. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +0 -1
  612. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
  613. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js +0 -1
  614. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
  615. mage_ai/shared/memory.py +0 -90
  616. mage_ai/tests/data_preparation/models/block/dynamic/test_dynamic_helpers.py +0 -48
  617. /mage_ai/{tests/data_preparation/shared → ai/utils}/__init__.py +0 -0
  618. /mage_ai/server/frontend_dist/_next/static/{_krrrgup_C-dPOpX36S8I → UZLabyPgcxtZvp0O0EUUS}/_ssgManifest.js +0 -0
  619. /mage_ai/server/frontend_dist_base_path_template/_next/static/{KLL5mirre9d7_ZeEpaw3s → kcptwoOU-JJJg6Vwpkfmx}/_ssgManifest.js +0 -0
  620. /mage_ai/tests/data_preparation/{shared → storage/shared}/test_secrets.py +0 -0
  621. {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/LICENSE +0 -0
  622. {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/WHEEL +0 -0
  623. {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/entry_points.txt +0 -0
  624. {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/top_level.txt +0 -0
@@ -2,14 +2,39 @@ import json
2
2
  import os
3
3
  from dataclasses import dataclass, field
4
4
  from enum import Enum
5
- from typing import Any, Dict, List, Tuple, Union
5
+ from typing import Any, Dict, List, Optional, Tuple, Union
6
6
 
7
7
  import pandas as pd
8
+ import polars as pl
9
+ from scipy.sparse import csr_matrix
8
10
 
11
+ from mage_ai.data_preparation.models.block.dynamic.shared import (
12
+ has_dynamic_block_upstream_parent as has_dynamic_block_upstream_parent_v1,
13
+ )
14
+ from mage_ai.data_preparation.models.block.dynamic.shared import (
15
+ has_reduce_output_from_upstreams as has_reduce_output_from_upstreams_v1,
16
+ )
17
+ from mage_ai.data_preparation.models.block.dynamic.shared import (
18
+ is_dynamic_block as is_dynamic_block_v1,
19
+ )
20
+ from mage_ai.data_preparation.models.block.dynamic.shared import (
21
+ is_dynamic_block_child as is_dynamic_block_child_v1,
22
+ )
23
+ from mage_ai.data_preparation.models.block.dynamic.shared import (
24
+ should_reduce_output as should_reduce_output_v1,
25
+ )
9
26
  from mage_ai.data_preparation.models.block.dynamic.variables import (
10
27
  get_outputs_for_dynamic_block,
11
28
  )
12
- from mage_ai.data_preparation.models.constants import DATAFRAME_ANALYSIS_MAX_COLUMNS
29
+ from mage_ai.data_preparation.models.constants import (
30
+ DATAFRAME_ANALYSIS_MAX_COLUMNS,
31
+ DATAFRAME_SAMPLE_COUNT_PREVIEW,
32
+ )
33
+ from mage_ai.data_preparation.models.utils import (
34
+ is_basic_iterable,
35
+ is_dataframe_or_series,
36
+ prepare_data_for_output,
37
+ )
13
38
  from mage_ai.server.kernel_output_parser import DataType
14
39
  from mage_ai.shared.array import find
15
40
  from mage_ai.shared.custom_logger import DX_PRINTER
@@ -73,66 +98,23 @@ def extract_dynamic_block_index(block_run_block_uuid: str) -> int:
73
98
 
74
99
 
75
100
  def is_dynamic_block(block) -> bool:
76
- """
77
- Checks if the given block is a dynamic block.
78
-
79
- Args:
80
- block: The block.
81
-
82
- Returns:
83
- bool: True if the block is a dynamic block, False otherwise.
84
- """
85
- return block and block.configuration and block.configuration.get('dynamic', False)
101
+ return is_dynamic_block_v1(block)
86
102
 
87
103
 
88
104
  def should_reduce_output(block) -> bool:
89
- """
90
- Checks if the given block should reduce its output.
91
-
92
- Args:
93
- block: The block.
94
-
95
- Returns:
96
- bool: True if the block should reduce its output, False otherwise.
97
- """
98
- if not block or not block.configuration or not block.configuration.get('reduce_output', False):
99
- return False
100
- return True
105
+ return should_reduce_output_v1(block)
101
106
 
102
107
 
103
108
  def has_reduce_output_from_upstreams(block) -> bool:
104
- return any([should_reduce_output(upstream_block) for upstream_block in block.upstream_blocks])
109
+ return has_reduce_output_from_upstreams_v1(block)
105
110
 
106
111
 
107
112
  def has_dynamic_block_upstream_parent(block) -> bool:
108
- return block.upstream_blocks and any([is_dynamic_block(b) for b in block.upstream_blocks])
109
-
110
-
111
- def is_dynamic_block_child(block) -> bool:
112
- """
113
- Checks if the given block is a dynamic block child.
113
+ return has_dynamic_block_upstream_parent_v1(block)
114
114
 
115
- Args:
116
- block: The block.
117
-
118
- Returns:
119
- bool: True if the block is a dynamic block child, False otherwise.
120
- """
121
- if not block:
122
- return False
123
-
124
- dynamic_or_child = []
125
115
 
126
- for upstream_block in block.upstream_blocks:
127
- if is_dynamic_block(upstream_block) or is_dynamic_block_child(upstream_block):
128
- dynamic_or_child.append(upstream_block)
129
-
130
- if len(dynamic_or_child) == 0:
131
- return False
132
-
133
- dynamic_or_child_with_reduce = list(filter(lambda x: should_reduce_output(x), dynamic_or_child))
134
-
135
- return len(dynamic_or_child) > len(dynamic_or_child_with_reduce)
116
+ def is_dynamic_block_child(block, include_reduce_output: Optional[bool] = None) -> bool:
117
+ return is_dynamic_block_child_v1(block, include_reduce_output=include_reduce_output)
136
118
 
137
119
 
138
120
  def is_replicated_block(block) -> bool:
@@ -149,6 +131,7 @@ def is_original_dynamic_child_block(
149
131
 
150
132
  def __get_block_run(block_run_id=block_run_id):
151
133
  from mage_ai.orchestration.db.models.schedules import BlockRun
134
+
152
135
  return BlockRun.query.get(block_run_id)
153
136
 
154
137
  if block:
@@ -176,10 +159,10 @@ def is_original_dynamic_child_block(
176
159
 
177
160
  def uuid_for_output_variables(
178
161
  block,
179
- block_uuid: str = None,
180
- dynamic_block_index: int = None,
181
- dynamic_block_uuid: str = None,
182
- join_character: str = None,
162
+ block_uuid: Optional[str] = None,
163
+ dynamic_block_index: Optional[int] = None,
164
+ dynamic_block_uuid: Optional[str] = None,
165
+ join_character: Optional[str] = None,
183
166
  **kwargs,
184
167
  ) -> Tuple[str, bool]:
185
168
  changed = False
@@ -196,9 +179,9 @@ def uuid_for_output_variables(
196
179
  return os.path.join(block.uuid, str(dynamic_block_index)), True
197
180
 
198
181
  is_dynamic = is_dynamic_block(block)
199
- if (not is_dynamic and (dynamic_block_index is None or is_dynamic_child)) or \
200
- (is_dynamic and is_dynamic_child):
201
-
182
+ if (not is_dynamic and (dynamic_block_index is None or is_dynamic_child)) or (
183
+ is_dynamic and is_dynamic_child
184
+ ):
202
185
  parts = block_uuid.split(':')
203
186
 
204
187
  if len(parts) >= 2:
@@ -236,26 +219,38 @@ def uuid_for_output_variables(
236
219
  return (block_uuid, changed)
237
220
 
238
221
 
239
- def transform_dataframe_for_display(dataframe: pd.DataFrame) -> Dict:
222
+ def transform_dataframe_for_display(
223
+ dataframe: pd.DataFrame,
224
+ is_dynamic: bool = False,
225
+ is_dynamic_child: bool = False,
226
+ sample_columns: int = DATAFRAME_ANALYSIS_MAX_COLUMNS,
227
+ sample_count: int = DATAFRAME_SAMPLE_COUNT_PREVIEW,
228
+ shape: Optional[Tuple[int, int]] = None,
229
+ ) -> Dict:
240
230
  data = None
231
+
232
+ column_name = '-'
233
+ if is_dynamic:
234
+ column_name = 'dynamic child blocks'
235
+ elif is_dynamic_child:
236
+ column_name = 'output'
237
+
241
238
  if isinstance(dataframe, pd.DataFrame):
242
- columns_to_display = dataframe.columns.tolist()[:DATAFRAME_ANALYSIS_MAX_COLUMNS]
243
- row_count, column_count = dataframe.shape
239
+ columns_to_display = dataframe.columns.tolist()[:sample_columns]
240
+ row_count, column_count = shape or dataframe.shape
241
+
242
+ df = dataframe.iloc[:sample_count][columns_to_display]
244
243
 
245
244
  data = dict(
246
245
  columns=columns_to_display,
247
- rows=json.loads(
248
- dataframe[columns_to_display].to_json(orient='split')
249
- )['data'],
250
- index=list(dataframe.index),
246
+ rows=json.loads(df.to_json(orient='split'))['data'],
251
247
  shape=[row_count, column_count],
252
248
  )
253
249
  else:
254
250
  data = dict(
255
- columns=['col0'],
256
- rows=[[dataframe]],
257
- index=[0],
258
- shape=[1, 1],
251
+ columns=[column_name],
252
+ rows=[[dataframe[:sample_count]]],
253
+ shape=list(shape) if shape else [1, 1],
259
254
  )
260
255
 
261
256
  return dict(
@@ -264,10 +259,26 @@ def transform_dataframe_for_display(dataframe: pd.DataFrame) -> Dict:
264
259
  )
265
260
 
266
261
 
267
- def coerce_into_dataframe(child_data: Union[
268
- List[Union[Dict, int, str, pd.DataFrame]],
269
- pd.DataFrame
270
- ]) -> Dict:
262
+ def coerce_into_dataframe(
263
+ child_data: Union[
264
+ List[Union[Dict, int, str, pd.DataFrame]],
265
+ Dict,
266
+ int,
267
+ str,
268
+ pd.DataFrame,
269
+ ],
270
+ is_dynamic: bool = False,
271
+ is_dynamic_child: bool = False,
272
+ single_item_only: bool = False,
273
+ ) -> pd.DataFrame:
274
+ child_data, _ = prepare_data_for_output(child_data, single_item_only=single_item_only)
275
+
276
+ column_name = '-'
277
+ if is_dynamic:
278
+ column_name = 'dynamic child blocks'
279
+ elif is_dynamic_child:
280
+ column_name = 'output'
281
+
271
282
  if isinstance(child_data, list) and len(child_data) >= 1:
272
283
  item = child_data[0]
273
284
  if isinstance(item, pd.DataFrame):
@@ -276,34 +287,51 @@ def coerce_into_dataframe(child_data: Union[
276
287
  child_data = pd.DataFrame(child_data)
277
288
  else:
278
289
  child_data = pd.DataFrame(
279
- [dict(col=value) for value in child_data],
290
+ [
291
+ {
292
+ column_name: value,
293
+ }
294
+ for value in child_data
295
+ ],
280
296
  )
281
- elif isinstance(child_data, pd.DataFrame):
297
+ elif isinstance(child_data, (pd.DataFrame, pl.DataFrame)):
282
298
  return child_data
283
299
  else:
284
- child_data = pd.DataFrame([dict(col=child_data)])
300
+ child_data = pd.DataFrame([
301
+ {
302
+ column_name: child_data,
303
+ }
304
+ ])
285
305
 
286
306
  return child_data
287
307
 
288
308
 
289
- def limit_output(output: Union[List, pd.DataFrame], sample_count: int) -> Union[List, pd.DataFrame]:
290
- if sample_count is not None:
291
- if output is not None:
292
- if isinstance(output, list):
293
- output = output[:sample_count]
294
- elif isinstance(output, pd.DataFrame):
309
+ def limit_output(
310
+ output: Union[List, pd.DataFrame, pd.Series, csr_matrix],
311
+ sample_count: int = DATAFRAME_SAMPLE_COUNT_PREVIEW,
312
+ sample_columns: Optional[int] = DATAFRAME_ANALYSIS_MAX_COLUMNS,
313
+ ) -> Union[List, pd.DataFrame, pd.Series, csr_matrix]:
314
+ if sample_count is not None and output is not None:
315
+ if isinstance(output, list):
316
+ output = output[:sample_count]
317
+ elif isinstance(output, pd.Series):
318
+ output = output.iloc[:sample_count]
319
+ elif isinstance(output, pd.DataFrame):
320
+ if sample_columns is not None:
321
+ output = output.iloc[:sample_count, :sample_columns]
322
+ else:
295
323
  output = output.iloc[:sample_count]
324
+ elif isinstance(output, csr_matrix):
325
+ output = output[:sample_count] # For csr_matrix, this slices rows
326
+ if sample_columns is not None:
327
+ output = output[:, :sample_columns]
296
328
  return output
297
329
 
298
330
 
299
331
  def transform_output(
300
- output: Tuple[
301
- Union[
302
- List[Union[Dict, int, str, pd.DataFrame]],
303
- pd.DataFrame
304
- ],
305
- List[Dict]
306
- ],
332
+ output: Tuple[Union[List[Union[Dict, int, str, pd.DataFrame]], pd.DataFrame], List[Dict]],
333
+ is_dynamic: bool = False,
334
+ is_dynamic_child: bool = False,
307
335
  ):
308
336
  child_data = None
309
337
  metadata = None
@@ -316,39 +344,66 @@ def transform_output(
316
344
  if child_data is None:
317
345
  return []
318
346
 
319
- child_data = coerce_into_dataframe(child_data)
347
+ child_data = coerce_into_dataframe(
348
+ child_data,
349
+ is_dynamic=is_dynamic,
350
+ is_dynamic_child=is_dynamic_child,
351
+ )
320
352
 
321
353
  if isinstance(child_data, tuple):
322
- return transform_output(child_data)
354
+ return transform_output(
355
+ child_data,
356
+ is_dynamic=is_dynamic,
357
+ is_dynamic_child=is_dynamic_child,
358
+ )
323
359
  elif isinstance(child_data, list):
324
- child_data = [transform_dataframe_for_display(data) for data in child_data]
360
+ child_data = [
361
+ transform_dataframe_for_display(
362
+ data,
363
+ is_dynamic=is_dynamic,
364
+ is_dynamic_child=is_dynamic_child,
365
+ )
366
+ for data in child_data
367
+ ]
325
368
  else:
326
- child_data = transform_dataframe_for_display(child_data)
369
+ child_data = transform_dataframe_for_display(
370
+ child_data,
371
+ is_dynamic=is_dynamic,
372
+ is_dynamic_child=is_dynamic_child,
373
+ )
327
374
 
328
375
  if metadata is not None:
329
- metadata = transform_dataframe_for_display(coerce_into_dataframe(metadata))
376
+ metadata = transform_dataframe_for_display(
377
+ coerce_into_dataframe(
378
+ metadata,
379
+ is_dynamic=is_dynamic,
380
+ is_dynamic_child=is_dynamic_child,
381
+ ),
382
+ is_dynamic=is_dynamic,
383
+ is_dynamic_child=is_dynamic_child,
384
+ )
330
385
 
331
386
  return child_data, metadata
332
387
 
333
388
 
334
389
  def transform_output_for_display(
335
- output: Tuple[
336
- Union[
337
- List[Union[Dict, int, str, pd.DataFrame]],
338
- pd.DataFrame
339
- ],
340
- List[Dict]
341
- ],
342
- sample_count: int = None,
390
+ output: Tuple[Union[List[Union[Dict, int, str, pd.DataFrame]], pd.DataFrame], List[Dict]],
391
+ is_dynamic: bool = False,
392
+ is_dynamic_child: bool = False,
393
+ sample_count: Optional[int] = None,
394
+ sample_columns: Optional[int] = None,
343
395
  ) -> List[Dict]:
344
- child_data, metadata = transform_output(output)
345
- child_data = limit_output(child_data, sample_count)
346
- metadata = limit_output(metadata, sample_count)
396
+ child_data, metadata = transform_output(
397
+ output,
398
+ is_dynamic=is_dynamic,
399
+ is_dynamic_child=is_dynamic_child,
400
+ )
401
+ child_data = limit_output(child_data, sample_count, sample_columns=sample_columns)
402
+ metadata = limit_output(metadata, sample_count, sample_columns=sample_columns)
347
403
 
348
404
  return dict(
349
405
  data=dict(
350
- columns=['child_data', 'metadata'],
351
- index=[0, 1],
406
+ columns=['dynamic children data', 'metadata'],
352
407
  rows=[child_data, metadata],
353
408
  shape=[2, 2],
354
409
  ),
@@ -359,34 +414,54 @@ def transform_output_for_display(
359
414
 
360
415
  def transform_output_for_display_reduce_output(
361
416
  output: List[Any],
362
- sample_count: int = None,
417
+ is_dynamic: bool = False,
418
+ is_dynamic_child: bool = False,
419
+ sample_count: Optional[int] = None,
420
+ sample_columns: Optional[int] = None,
363
421
  ) -> List[Dict]:
364
- output = limit_output(output, sample_count)
422
+ output = [
423
+ limit_output(
424
+ values,
425
+ sample_count=sample_count,
426
+ sample_columns=sample_columns,
427
+ )
428
+ for values in output
429
+ ]
365
430
 
366
- arr = [dict(
367
- text_data=data,
368
- type=DataType.TEXT,
369
- variable_uuid=f'output_{idx}',
370
- ) for idx, data in enumerate(output)]
431
+ output = limit_output(output, sample_count=sample_count, sample_columns=sample_columns)
432
+
433
+ arr = [
434
+ dict(
435
+ text_data=data,
436
+ type=DataType.TEXT,
437
+ variable_uuid=f'reduced output {idx}',
438
+ )
439
+ for idx, data in enumerate(output)
440
+ ]
371
441
 
372
442
  return arr
373
443
 
374
444
 
375
- def combine_transformed_output_for_multi_output(transform_outputs: List[Dict]):
376
- columns = []
377
- index = []
445
+ def combine_transformed_output_for_multi_output(
446
+ transform_outputs: List[Dict],
447
+ columns: Optional[List[str]] = None,
448
+ is_grouping: bool = False,
449
+ ) -> Dict[str, Union[DataType, Dict, bool, str]]:
450
+ columns_use = columns or []
378
451
  for i in range(len(transform_outputs)):
379
- columns.append(f'child_{i}')
380
- index.append(i)
452
+ if not columns:
453
+ columns_use.append(f'output {i}')
381
454
 
382
455
  return dict(
383
456
  data=dict(
384
- columns=columns,
385
- index=index,
457
+ columns=columns_use,
386
458
  rows=transform_outputs,
387
- shape=[len(transform_outputs), len(columns)],
459
+ shape=[
460
+ len(transform_outputs),
461
+ len(columns_use),
462
+ ],
388
463
  ),
389
- type=DataType.TABLE,
464
+ type=DataType.GROUP if is_grouping else DataType.TABLE,
390
465
  multi_output=True,
391
466
  )
392
467
 
@@ -398,25 +473,41 @@ def transform_output_for_display_dynamic_child(
398
473
  Dict,
399
474
  int,
400
475
  str,
401
- pd.DataFrame
402
- ]
476
+ pd.DataFrame,
477
+ ],
403
478
  ],
404
479
  is_dynamic: bool = False,
405
- sample_count: int = None,
480
+ is_dynamic_child: bool = False,
481
+ single_item_only: bool = False,
406
482
  ) -> List[Dict]:
407
483
  df = None
408
484
  for output_from_variable_object in output:
409
- df_inner = coerce_into_dataframe(output_from_variable_object)
485
+ df_inner = coerce_into_dataframe(
486
+ output_from_variable_object,
487
+ is_dynamic=is_dynamic,
488
+ is_dynamic_child=is_dynamic_child,
489
+ single_item_only=single_item_only,
490
+ )
410
491
  if df is None:
411
492
  df = df_inner
412
493
  else:
413
- df = pd.concat([df, df_inner], axis=1)
414
-
415
- df = limit_output(df, sample_count)
416
- if 1 == len(set(df.columns)):
417
- df.columns = [f'{col}_{idx}' for idx, col in enumerate(df.columns)]
418
-
419
- return transform_dataframe_for_display(df)
494
+ df.reset_index(drop=True, inplace=True)
495
+ df_inner.reset_index(drop=True, inplace=True)
496
+ df = pd.concat([df, df_inner], axis=1, ignore_index=True)
497
+
498
+ shape = None
499
+ if hasattr(df, 'shape'):
500
+ shape = df.shape
501
+
502
+ if isinstance(df, pd.DataFrame) and len(set(df.columns)) == 1:
503
+ df.columns = [str(idx) for idx, col in enumerate(df.columns)]
504
+
505
+ return transform_dataframe_for_display(
506
+ df,
507
+ is_dynamic=is_dynamic,
508
+ is_dynamic_child=is_dynamic_child,
509
+ shape=shape,
510
+ )
420
511
 
421
512
 
422
513
  def create_combinations(combinations: List[Any]) -> List[Any]:
@@ -425,7 +516,7 @@ def create_combinations(combinations: List[Any]) -> List[Any]:
425
516
 
426
517
  for idx, arr in enumerate(combinations_inner):
427
518
  for value in arr:
428
- combinations_next = combinations_inner[(idx + 1):]
519
+ combinations_next = combinations_inner[(idx + 1) :]
429
520
  if len(combinations_next) >= 1:
430
521
  for combos_down in __create_combinations(combinations_next):
431
522
  combos.append([value] + combos_down)
@@ -442,6 +533,7 @@ def create_combinations(combinations: List[Any]) -> List[Any]:
442
533
  def build_combinations_for_dynamic_child(
443
534
  block,
444
535
  execution_partition: str = None,
536
+ origin_block: Optional[Any] = None,
445
537
  **kwargs,
446
538
  ):
447
539
  """
@@ -464,6 +556,9 @@ def build_combinations_for_dynamic_child(
464
556
  [0, 1],
465
557
  ]
466
558
  """
559
+ if origin_block is None:
560
+ origin_block = block
561
+
467
562
  dynamic_counts = []
468
563
 
469
564
  for upstream_block in block.upstream_blocks:
@@ -488,16 +583,22 @@ def build_combinations_for_dynamic_child(
488
583
  children_created = build_combinations_for_dynamic_child(
489
584
  upstream_block,
490
585
  execution_partition=execution_partition,
586
+ origin_block=origin_block,
491
587
  )
492
588
  if is_dynamic:
493
589
  for dynamic_block_index in range(len(children_created)):
494
590
  values, _metadata = get_outputs_for_dynamic_block(
495
591
  upstream_block,
496
592
  execution_partition=execution_partition,
497
- dynamic_block_index=dynamic_block_index
593
+ dynamic_block_index=dynamic_block_index,
594
+ origin_block=origin_block,
498
595
  )
499
596
  if values is not None:
500
- arr.extend([idx for idx in range(len(values))])
597
+ if is_basic_iterable(values) or is_dataframe_or_series(values):
598
+ count = len(values)
599
+ else:
600
+ count = 1
601
+ arr.extend([idx for idx in range(count)])
501
602
  else:
502
603
  arr.append(0)
503
604
  else:
@@ -506,8 +607,12 @@ def build_combinations_for_dynamic_child(
506
607
  arr, _metadata = get_outputs_for_dynamic_block(
507
608
  upstream_block,
508
609
  execution_partition=execution_partition,
610
+ origin_block=origin_block,
509
611
  )
510
- if arr is not None:
612
+ if arr is not None:
613
+ if not is_basic_iterable(arr) and not is_dataframe_or_series(arr):
614
+ arr = [0]
615
+ if arr is not None and hasattr(arr, '__len__') and len(arr) > 0:
511
616
  dynamic_counts.append([idx for idx in range(len(arr))])
512
617
  else:
513
618
  dynamic_counts.append([0])
@@ -537,10 +642,12 @@ def build_combinations_for_dynamic_child(
537
642
  if is_dynamic_child or is_dynamic:
538
643
  dynamic_block_indexes[upstream_block.uuid] = parent_index
539
644
 
540
- settings.append(dict(
541
- dynamic_block_index=dynamic_block_index,
542
- dynamic_block_indexes=dynamic_block_indexes,
543
- ))
645
+ settings.append(
646
+ dict(
647
+ dynamic_block_index=dynamic_block_index,
648
+ dynamic_block_indexes=dynamic_block_indexes,
649
+ )
650
+ )
544
651
 
545
652
  return settings
546
653
 
@@ -591,7 +698,9 @@ class DynamicBlockWrapper(BaseDataClass):
591
698
  # Upstream blocks that are dynamic blocks.
592
699
  upstream_dynamic_blocks: List[DynamicBlockWrapperBase] = field(default_factory=lambda: [])
593
700
  # Upstream blocks that are dynamic child blocks.
594
- upstream_dynamic_child_blocks: List[DynamicBlockWrapperBase] = field(default_factory=lambda: [])
701
+ upstream_dynamic_child_blocks: List[DynamicBlockWrapperBase] = field(
702
+ default_factory=lambda: []
703
+ )
595
704
  # Unique identifier used as a suffix in the block run.
596
705
  uuid: str = None
597
706
 
@@ -645,8 +754,9 @@ class DynamicBlockWrapper(BaseDataClass):
645
754
  if not self.block:
646
755
  return False
647
756
 
648
- return self.block.uuid == self.block_run_block_uuid or \
649
- (self.is_replicated() and self.block.uuid_replicated == self.block_run_block_uuid)
757
+ return self.block.uuid == self.block_run_block_uuid or (
758
+ self.is_replicated() and self.block.uuid_replicated == self.block_run_block_uuid
759
+ )
650
760
 
651
761
  def is_replicated(self) -> bool:
652
762
  return DynamicBlockFlag.REPLICATED in (self.flags or []) or is_replicated_block(self.block)
@@ -671,11 +781,15 @@ class DynamicBlockWrapper(BaseDataClass):
671
781
  if DynamicBlockFlag.SPAWN_OF_DYNAMIC_CHILD in (self.flags or []):
672
782
  return True
673
783
 
674
- return (self.block or self.block_uuid) and \
675
- self.block_run_block_uuid and \
676
- ((self.block and self.block.uuid != self.block_run_block_uuid) or
677
- (self.block_uuid and self.block_uuid != self.block_run_block_uuid)) and \
678
- not self.is_original(include_clone=True)
784
+ return (
785
+ (self.block or self.block_uuid)
786
+ and self.block_run_block_uuid
787
+ and (
788
+ (self.block and self.block.uuid != self.block_run_block_uuid)
789
+ or (self.block_uuid and self.block_uuid != self.block_run_block_uuid)
790
+ )
791
+ and not self.is_original(include_clone=True)
792
+ )
679
793
 
680
794
  def should_reduce_output(self) -> bool:
681
795
  if DynamicBlockFlag.REDUCE_OUTPUT in (self.flags or []):
@@ -764,11 +878,13 @@ class DynamicBlockWrapper(BaseDataClass):
764
878
  **kwargs,
765
879
  ) -> dict:
766
880
  if use_metadata_instructions:
767
- return ignore_keys_with_blank_values(dict(
768
- clone_original=self.metadata_instructions.clone_original,
769
- original=self.metadata_instructions.original.to_dict_base(),
770
- upstream=self.metadata_instructions.upstream.to_dict_base(),
771
- ))
881
+ return ignore_keys_with_blank_values(
882
+ dict(
883
+ clone_original=self.metadata_instructions.clone_original,
884
+ original=self.metadata_instructions.original.to_dict_base(),
885
+ upstream=self.metadata_instructions.upstream.to_dict_base(),
886
+ )
887
+ )
772
888
 
773
889
  data = self.to_dict_base(**kwargs)
774
890
  if include_all:
@@ -901,11 +1017,14 @@ def check_all_dynamic_upstreams_completed(
901
1017
 
902
1018
  from mage_ai.orchestration.db.models.schedules import BlockRun
903
1019
 
904
- upstreams_done = all([check_all_dynamic_upstreams_completed(
905
- b,
906
- block_runs=block_runs,
907
- execution_partition=execution_partition,
908
- ) for b in upstream_block.upstream_blocks])
1020
+ upstreams_done = all([
1021
+ check_all_dynamic_upstreams_completed(
1022
+ b,
1023
+ block_runs=block_runs,
1024
+ execution_partition=execution_partition,
1025
+ )
1026
+ for b in upstream_block.upstream_blocks
1027
+ ])
909
1028
 
910
1029
  if not upstreams_done:
911
1030
  return False
@@ -917,17 +1036,26 @@ def check_all_dynamic_upstreams_completed(
917
1036
  execution_partition=execution_partition,
918
1037
  )
919
1038
 
920
- selected = [br for br in block_runs if pipeline.get_block(
921
- br.block_uuid,
922
- ).uuid == upstream_block.uuid and br.status == BlockRun.BlockRunStatus.COMPLETED]
1039
+ selected = [
1040
+ br
1041
+ for br in block_runs
1042
+ if pipeline.get_block(
1043
+ br.block_uuid,
1044
+ ).uuid
1045
+ == upstream_block.uuid
1046
+ and br.status == BlockRun.BlockRunStatus.COMPLETED
1047
+ ]
923
1048
 
924
1049
  if len(list(selected)) < len(combos) + 1:
925
1050
  return False
926
1051
 
927
- return all([br.status == BlockRun.BlockRunStatus.COMPLETED for br in filter(
928
- lambda br: pipeline.get_block(br.block_uuid).uuid == upstream_block.uuid,
929
- block_runs,
930
- )])
1052
+ return all([
1053
+ br.status == BlockRun.BlockRunStatus.COMPLETED
1054
+ for br in filter(
1055
+ lambda br: pipeline.get_block(br.block_uuid).uuid == upstream_block.uuid,
1056
+ block_runs,
1057
+ )
1058
+ ])
931
1059
 
932
1060
  # 1. Are all the upstream blocks for my upstream blocks completed?
933
1061
  # 2. Then, are my immediate upstream blocks completed?