mage-ai 0.9.70__py3-none-any.whl → 0.9.71__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mage-ai might be problematic. Click here for more details.

Files changed (568) hide show
  1. mage_ai/ai/utils/xgboost.py +222 -0
  2. mage_ai/api/errors.py +37 -25
  3. mage_ai/api/operations/base.py +13 -1
  4. mage_ai/api/parsers/PipelineScheduleParser.py +1 -1
  5. mage_ai/api/policies/BlockOutputPolicy.py +40 -17
  6. mage_ai/api/policies/GlobalDataProductPolicy.py +91 -41
  7. mage_ai/api/policies/KernelPolicy.py +55 -32
  8. mage_ai/api/policies/KernelProcessPolicy.py +56 -0
  9. mage_ai/api/policies/OutputPolicy.py +73 -41
  10. mage_ai/api/policies/PipelinePolicy.py +206 -138
  11. mage_ai/api/presenters/BlockLayoutItemPresenter.py +9 -7
  12. mage_ai/api/presenters/BlockPresenter.py +1 -1
  13. mage_ai/api/presenters/GlobalDataProductPresenter.py +6 -1
  14. mage_ai/api/presenters/KernelPresenter.py +5 -26
  15. mage_ai/api/presenters/KernelProcessPresenter.py +28 -0
  16. mage_ai/api/presenters/PipelinePresenter.py +18 -5
  17. mage_ai/api/presenters/StatusPresenter.py +2 -0
  18. mage_ai/api/presenters/SyncPresenter.py +25 -0
  19. mage_ai/api/resources/AutocompleteItemResource.py +1 -1
  20. mage_ai/api/resources/BlockLayoutItemResource.py +90 -44
  21. mage_ai/api/resources/BlockOutputResource.py +42 -9
  22. mage_ai/api/resources/BlockResource.py +4 -3
  23. mage_ai/api/resources/BlockRunResource.py +27 -22
  24. mage_ai/api/resources/ClusterResource.py +4 -1
  25. mage_ai/api/resources/CustomTemplateResource.py +34 -14
  26. mage_ai/api/resources/DataProviderResource.py +1 -1
  27. mage_ai/api/resources/ExecutionStateResource.py +3 -1
  28. mage_ai/api/resources/FileContentResource.py +8 -2
  29. mage_ai/api/resources/FileResource.py +10 -4
  30. mage_ai/api/resources/FileVersionResource.py +3 -1
  31. mage_ai/api/resources/GitBranchResource.py +46 -9
  32. mage_ai/api/resources/GlobalDataProductResource.py +44 -7
  33. mage_ai/api/resources/GlobalHookResource.py +4 -1
  34. mage_ai/api/resources/IntegrationDestinationResource.py +6 -2
  35. mage_ai/api/resources/IntegrationSourceResource.py +8 -4
  36. mage_ai/api/resources/IntegrationSourceStreamResource.py +6 -2
  37. mage_ai/api/resources/KernelProcessResource.py +44 -0
  38. mage_ai/api/resources/KernelResource.py +25 -3
  39. mage_ai/api/resources/OutputResource.py +33 -11
  40. mage_ai/api/resources/PageBlockLayoutResource.py +34 -23
  41. mage_ai/api/resources/PipelineInteractionResource.py +31 -15
  42. mage_ai/api/resources/PipelineResource.py +250 -123
  43. mage_ai/api/resources/PipelineRunResource.py +11 -3
  44. mage_ai/api/resources/PipelineScheduleResource.py +7 -2
  45. mage_ai/api/resources/PipelineTriggerResource.py +6 -1
  46. mage_ai/api/resources/ProjectResource.py +18 -7
  47. mage_ai/api/resources/SecretResource.py +1 -1
  48. mage_ai/api/resources/SeedResource.py +8 -1
  49. mage_ai/api/resources/StatusResource.py +21 -6
  50. mage_ai/api/resources/SyncResource.py +6 -8
  51. mage_ai/api/resources/VariableResource.py +46 -26
  52. mage_ai/api/resources/VersionControlProjectResource.py +9 -2
  53. mage_ai/api/resources/WidgetResource.py +1 -1
  54. mage_ai/api/resources/WorkspaceResource.py +1 -1
  55. mage_ai/api/views.py +47 -40
  56. mage_ai/authentication/permissions/seed.py +16 -2
  57. mage_ai/authentication/providers/oidc.py +21 -1
  58. mage_ai/autocomplete/utils.py +13 -9
  59. mage_ai/cache/base.py +1 -1
  60. mage_ai/cache/block.py +18 -12
  61. mage_ai/cache/block_action_object/__init__.py +32 -4
  62. mage_ai/cache/file.py +22 -19
  63. mage_ai/cache/pipeline.py +18 -12
  64. mage_ai/cli/main.py +1 -0
  65. mage_ai/cluster_manager/aws/emr_cluster_manager.py +9 -5
  66. mage_ai/cluster_manager/config.py +2 -2
  67. mage_ai/cluster_manager/manage.py +1 -1
  68. mage_ai/cluster_manager/workspace/base.py +1 -1
  69. mage_ai/command_center/applications/factory.py +10 -7
  70. mage_ai/command_center/files/factory.py +17 -15
  71. mage_ai/command_center/utils.py +25 -13
  72. mage_ai/data/__init__.py +0 -0
  73. mage_ai/data/constants.py +45 -0
  74. mage_ai/data/models/__init__.py +0 -0
  75. mage_ai/data/models/base.py +119 -0
  76. mage_ai/data/models/constants.py +1 -0
  77. mage_ai/data/models/generator.py +115 -0
  78. mage_ai/data/models/manager.py +168 -0
  79. mage_ai/data/models/pyarrow/__init__.py +0 -0
  80. mage_ai/data/models/pyarrow/record_batch.py +55 -0
  81. mage_ai/data/models/pyarrow/shared.py +21 -0
  82. mage_ai/data/models/pyarrow/table.py +8 -0
  83. mage_ai/data/models/reader.py +103 -0
  84. mage_ai/data/models/utils.py +59 -0
  85. mage_ai/data/models/writer.py +91 -0
  86. mage_ai/data/tabular/__init__.py +0 -0
  87. mage_ai/data/tabular/constants.py +23 -0
  88. mage_ai/data/tabular/mocks.py +19 -0
  89. mage_ai/data/tabular/models.py +126 -0
  90. mage_ai/data/tabular/reader.py +602 -0
  91. mage_ai/data/tabular/utils.py +102 -0
  92. mage_ai/data/tabular/writer.py +266 -0
  93. mage_ai/data/variables/__init__.py +0 -0
  94. mage_ai/data/variables/wrapper.py +54 -0
  95. mage_ai/data_cleaner/analysis/charts.py +61 -39
  96. mage_ai/data_cleaner/column_types/column_type_detector.py +53 -31
  97. mage_ai/data_cleaner/estimators/encoders.py +5 -2
  98. mage_ai/data_integrations/utils/scheduler.py +16 -11
  99. mage_ai/data_preparation/decorators.py +1 -0
  100. mage_ai/data_preparation/executors/block_executor.py +237 -155
  101. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +1 -1
  102. mage_ai/data_preparation/git/__init__.py +27 -7
  103. mage_ai/data_preparation/git/api.py +7 -1
  104. mage_ai/data_preparation/git/utils.py +22 -16
  105. mage_ai/data_preparation/logging/logger_manager.py +4 -3
  106. mage_ai/data_preparation/models/block/__init__.py +1542 -878
  107. mage_ai/data_preparation/models/block/data_integration/mixins.py +4 -3
  108. mage_ai/data_preparation/models/block/dynamic/__init__.py +17 -6
  109. mage_ai/data_preparation/models/block/dynamic/child.py +41 -102
  110. mage_ai/data_preparation/models/block/dynamic/constants.py +1 -0
  111. mage_ai/data_preparation/models/block/dynamic/counter.py +296 -0
  112. mage_ai/data_preparation/models/block/dynamic/data.py +16 -0
  113. mage_ai/data_preparation/models/block/dynamic/factory.py +163 -0
  114. mage_ai/data_preparation/models/block/dynamic/models.py +19 -0
  115. mage_ai/data_preparation/models/block/dynamic/shared.py +92 -0
  116. mage_ai/data_preparation/models/block/dynamic/utils.py +291 -168
  117. mage_ai/data_preparation/models/block/dynamic/variables.py +384 -144
  118. mage_ai/data_preparation/models/block/dynamic/wrappers.py +77 -0
  119. mage_ai/data_preparation/models/block/extension/utils.py +10 -1
  120. mage_ai/data_preparation/models/block/global_data_product/__init__.py +10 -1
  121. mage_ai/data_preparation/models/block/integration/__init__.py +6 -2
  122. mage_ai/data_preparation/models/block/outputs.py +722 -0
  123. mage_ai/data_preparation/models/block/platform/mixins.py +7 -8
  124. mage_ai/data_preparation/models/block/r/__init__.py +56 -38
  125. mage_ai/data_preparation/models/block/settings/__init__.py +0 -0
  126. mage_ai/data_preparation/models/block/settings/dynamic/__init__.py +0 -0
  127. mage_ai/data_preparation/models/block/settings/dynamic/constants.py +7 -0
  128. mage_ai/data_preparation/models/block/settings/dynamic/mixins.py +118 -0
  129. mage_ai/data_preparation/models/block/settings/dynamic/models.py +31 -0
  130. mage_ai/data_preparation/models/block/settings/global_data_products/__init__.py +0 -0
  131. mage_ai/data_preparation/models/block/settings/global_data_products/mixins.py +20 -0
  132. mage_ai/data_preparation/models/block/settings/global_data_products/models.py +46 -0
  133. mage_ai/data_preparation/models/block/settings/variables/__init__.py +0 -0
  134. mage_ai/data_preparation/models/block/settings/variables/mixins.py +74 -0
  135. mage_ai/data_preparation/models/block/settings/variables/models.py +49 -0
  136. mage_ai/data_preparation/models/block/spark/mixins.py +2 -1
  137. mage_ai/data_preparation/models/block/sql/__init__.py +30 -5
  138. mage_ai/data_preparation/models/block/sql/utils/shared.py +21 -3
  139. mage_ai/data_preparation/models/block/utils.py +127 -70
  140. mage_ai/data_preparation/models/constants.py +19 -14
  141. mage_ai/data_preparation/models/custom_templates/custom_block_template.py +18 -13
  142. mage_ai/data_preparation/models/custom_templates/custom_pipeline_template.py +33 -16
  143. mage_ai/data_preparation/models/custom_templates/utils.py +1 -1
  144. mage_ai/data_preparation/models/file.py +41 -28
  145. mage_ai/data_preparation/models/global_data_product/__init__.py +88 -58
  146. mage_ai/data_preparation/models/global_hooks/models.py +1 -0
  147. mage_ai/data_preparation/models/interfaces.py +29 -0
  148. mage_ai/data_preparation/models/pipeline.py +365 -180
  149. mage_ai/data_preparation/models/pipelines/integration_pipeline.py +1 -2
  150. mage_ai/data_preparation/models/pipelines/seed.py +1 -1
  151. mage_ai/data_preparation/models/project/__init__.py +66 -18
  152. mage_ai/data_preparation/models/project/constants.py +2 -0
  153. mage_ai/data_preparation/models/triggers/__init__.py +120 -24
  154. mage_ai/data_preparation/models/utils.py +467 -17
  155. mage_ai/data_preparation/models/variable.py +1028 -137
  156. mage_ai/data_preparation/models/variables/__init__.py +0 -0
  157. mage_ai/data_preparation/models/variables/cache.py +149 -0
  158. mage_ai/data_preparation/models/variables/constants.py +72 -0
  159. mage_ai/data_preparation/models/variables/summarizer.py +336 -0
  160. mage_ai/data_preparation/models/variables/utils.py +77 -0
  161. mage_ai/data_preparation/models/widget/__init__.py +63 -41
  162. mage_ai/data_preparation/models/widget/charts.py +40 -27
  163. mage_ai/data_preparation/models/widget/constants.py +2 -0
  164. mage_ai/data_preparation/models/widget/utils.py +3 -3
  165. mage_ai/data_preparation/preferences.py +3 -3
  166. mage_ai/data_preparation/repo_manager.py +55 -21
  167. mage_ai/data_preparation/storage/base_storage.py +2 -2
  168. mage_ai/data_preparation/storage/gcs_storage.py +7 -4
  169. mage_ai/data_preparation/storage/local_storage.py +6 -3
  170. mage_ai/data_preparation/storage/s3_storage.py +5 -2
  171. mage_ai/data_preparation/templates/data_exporters/streaming/oracledb.yaml +8 -0
  172. mage_ai/data_preparation/variable_manager.py +281 -76
  173. mage_ai/io/base.py +3 -2
  174. mage_ai/io/bigquery.py +1 -0
  175. mage_ai/io/redshift.py +7 -5
  176. mage_ai/kernels/__init__.py +0 -0
  177. mage_ai/kernels/models.py +188 -0
  178. mage_ai/kernels/utils.py +169 -0
  179. mage_ai/orchestration/concurrency.py +6 -2
  180. mage_ai/orchestration/db/__init__.py +1 -0
  181. mage_ai/orchestration/db/migrations/versions/0227396a216c_add_userproject_table.py +38 -0
  182. mage_ai/orchestration/db/models/dynamic/__init__.py +0 -0
  183. mage_ai/orchestration/db/models/dynamic/controller.py +67 -0
  184. mage_ai/orchestration/db/models/oauth.py +2 -9
  185. mage_ai/orchestration/db/models/projects.py +10 -0
  186. mage_ai/orchestration/db/models/schedules.py +204 -187
  187. mage_ai/orchestration/db/models/schedules_project_platform.py +18 -12
  188. mage_ai/orchestration/db/models/utils.py +46 -5
  189. mage_ai/orchestration/metrics/pipeline_run.py +8 -9
  190. mage_ai/orchestration/notification/sender.py +1 -0
  191. mage_ai/orchestration/pipeline_scheduler_original.py +32 -8
  192. mage_ai/orchestration/pipeline_scheduler_project_platform.py +1 -1
  193. mage_ai/orchestration/run_status_checker.py +11 -4
  194. mage_ai/orchestration/triggers/api.py +12 -1
  195. mage_ai/presenters/charts/data_sources/base.py +4 -2
  196. mage_ai/presenters/charts/data_sources/block.py +15 -9
  197. mage_ai/presenters/charts/data_sources/chart_code.py +8 -5
  198. mage_ai/presenters/charts/data_sources/constants.py +1 -0
  199. mage_ai/presenters/charts/data_sources/system_metrics.py +22 -0
  200. mage_ai/presenters/interactions/models.py +11 -7
  201. mage_ai/presenters/pages/loaders/pipelines.py +5 -3
  202. mage_ai/presenters/pages/models/page_components/pipeline_schedules.py +3 -1
  203. mage_ai/presenters/utils.py +2 -0
  204. mage_ai/server/api/blocks.py +2 -1
  205. mage_ai/server/api/downloads.py +5 -1
  206. mage_ai/server/api/triggers.py +3 -1
  207. mage_ai/server/constants.py +1 -1
  208. mage_ai/server/frontend_dist/404.html +5 -5
  209. mage_ai/server/frontend_dist/_next/static/UZLabyPgcxtZvp0O0EUUS/_buildManifest.js +1 -0
  210. mage_ai/server/frontend_dist/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
  211. mage_ai/server/frontend_dist/_next/static/chunks/{1557-b3502f3f1aa92ac7.js → 1557-25a7d985d5564fd3.js} +1 -1
  212. mage_ai/server/frontend_dist/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
  213. mage_ai/server/frontend_dist/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
  214. mage_ai/server/frontend_dist/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
  215. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3763-61b542dafdbf5754.js → frontend_dist/_next/static/chunks/3763-40780c6d1e4b261d.js} +1 -1
  216. mage_ai/server/frontend_dist/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
  217. mage_ai/server/frontend_dist/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
  218. mage_ai/server/frontend_dist/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
  219. mage_ai/server/frontend_dist/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
  220. mage_ai/server/frontend_dist/_next/static/chunks/5699-176f445e1313f001.js +1 -0
  221. mage_ai/server/frontend_dist/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
  222. mage_ai/server/frontend_dist/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
  223. mage_ai/server/frontend_dist/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
  224. mage_ai/server/frontend_dist/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
  225. mage_ai/server/frontend_dist/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
  226. mage_ai/server/frontend_dist/_next/static/chunks/{main-77fe248a6fbd12d8.js → main-b99d4e30a88d9dc7.js} +1 -1
  227. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-9fe2d9d07c94e968.js +1 -0
  228. mage_ai/server/frontend_dist/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
  229. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
  230. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
  231. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/overview-597b74828bf105db.js → frontend_dist/_next/static/chunks/pages/overview-9f1ac4ec003884f3.js} +1 -1
  232. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-7181b086c93784d2.js → [...slug]-7e737f6fc7e83e9b.js} +1 -1
  233. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
  234. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
  235. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
  236. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
  237. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-7acc7afc00df17c2.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-5f4c8128b2413fd8.js} +1 -1
  238. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
  239. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
  240. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
  241. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js → frontend_dist/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js} +1 -1
  242. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js → frontend_dist/_next/static/chunks/pages/settings/platform/settings-319ddbabc239e91b.js} +1 -1
  243. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
  244. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
  245. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
  246. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
  247. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
  248. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
  249. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
  250. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
  251. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
  252. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-d079359c241db804.js → webpack-ac7fdc472bedf682.js} +1 -1
  253. mage_ai/server/frontend_dist/block-layout.html +3 -3
  254. mage_ai/server/frontend_dist/compute.html +6 -6
  255. mage_ai/server/frontend_dist/files.html +6 -6
  256. mage_ai/server/frontend_dist/global-data-products/[...slug].html +6 -6
  257. mage_ai/server/frontend_dist/global-data-products.html +6 -6
  258. mage_ai/server/frontend_dist/global-hooks/[...slug].html +6 -6
  259. mage_ai/server/frontend_dist/global-hooks.html +6 -6
  260. mage_ai/server/frontend_dist/index.html +3 -3
  261. mage_ai/server/frontend_dist/manage/files.html +6 -6
  262. mage_ai/server/frontend_dist/manage/settings.html +6 -6
  263. mage_ai/server/frontend_dist/manage/users/[user].html +6 -6
  264. mage_ai/server/frontend_dist/manage/users/new.html +6 -6
  265. mage_ai/server/frontend_dist/manage/users.html +6 -6
  266. mage_ai/server/frontend_dist/manage.html +6 -6
  267. mage_ai/server/frontend_dist/oauth.html +5 -5
  268. mage_ai/server/frontend_dist/overview.html +6 -6
  269. mage_ai/server/frontend_dist/pipeline-runs.html +6 -6
  270. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  271. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +6 -6
  272. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +6 -6
  273. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +3 -3
  274. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +6 -6
  275. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  276. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  277. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +6 -6
  278. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +6 -6
  279. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +6 -6
  280. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +6 -6
  281. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +6 -6
  282. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  283. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +6 -6
  284. mage_ai/server/frontend_dist/pipelines/[pipeline].html +3 -3
  285. mage_ai/server/frontend_dist/pipelines.html +6 -6
  286. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +6 -6
  287. mage_ai/server/frontend_dist/platform/global-hooks.html +6 -6
  288. mage_ai/server/frontend_dist/settings/account/profile.html +6 -6
  289. mage_ai/server/frontend_dist/settings/platform/preferences.html +6 -6
  290. mage_ai/server/frontend_dist/settings/platform/settings.html +6 -6
  291. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +6 -6
  292. mage_ai/server/frontend_dist/settings/workspace/permissions.html +6 -6
  293. mage_ai/server/frontend_dist/settings/workspace/preferences.html +6 -6
  294. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +6 -6
  295. mage_ai/server/frontend_dist/settings/workspace/roles.html +6 -6
  296. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +6 -6
  297. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +6 -6
  298. mage_ai/server/frontend_dist/settings/workspace/users.html +6 -6
  299. mage_ai/server/frontend_dist/settings.html +3 -3
  300. mage_ai/server/frontend_dist/sign-in.html +12 -12
  301. mage_ai/server/frontend_dist/templates/[...slug].html +6 -6
  302. mage_ai/server/frontend_dist/templates.html +6 -6
  303. mage_ai/server/frontend_dist/terminal.html +6 -6
  304. mage_ai/server/frontend_dist/test.html +3 -3
  305. mage_ai/server/frontend_dist/triggers.html +6 -6
  306. mage_ai/server/frontend_dist/version-control.html +6 -6
  307. mage_ai/server/frontend_dist_base_path_template/404.html +5 -5
  308. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
  309. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1557-b3502f3f1aa92ac7.js → 1557-25a7d985d5564fd3.js} +1 -1
  310. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
  311. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
  312. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
  313. mage_ai/server/{frontend_dist/_next/static/chunks/3763-61b542dafdbf5754.js → frontend_dist_base_path_template/_next/static/chunks/3763-40780c6d1e4b261d.js} +1 -1
  314. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
  315. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
  316. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
  317. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
  318. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-176f445e1313f001.js +1 -0
  319. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
  320. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
  321. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
  322. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
  323. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
  324. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{main-70b78159c2bb3fe1.js → main-384298e9133cec76.js} +1 -1
  325. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-13a578bce3b7f30c.js +1 -0
  326. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
  327. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
  328. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
  329. mage_ai/server/{frontend_dist/_next/static/chunks/pages/overview-597b74828bf105db.js → frontend_dist_base_path_template/_next/static/chunks/pages/overview-9f1ac4ec003884f3.js} +1 -1
  330. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-7181b086c93784d2.js → [...slug]-7e737f6fc7e83e9b.js} +1 -1
  331. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
  332. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
  333. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
  334. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
  335. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-7acc7afc00df17c2.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-5f4c8128b2413fd8.js} +1 -1
  336. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
  337. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
  338. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
  339. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js} +1 -1
  340. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-319ddbabc239e91b.js} +1 -1
  341. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
  342. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
  343. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
  344. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
  345. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
  346. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
  347. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
  348. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
  349. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
  350. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-68c003fb6a175cd7.js → webpack-481689d9989710cd.js} +1 -1
  351. mage_ai/server/frontend_dist_base_path_template/_next/static/kcptwoOU-JJJg6Vwpkfmx/_buildManifest.js +1 -0
  352. mage_ai/server/frontend_dist_base_path_template/block-layout.html +3 -3
  353. mage_ai/server/frontend_dist_base_path_template/compute.html +6 -6
  354. mage_ai/server/frontend_dist_base_path_template/files.html +6 -6
  355. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +6 -6
  356. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +6 -6
  357. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +6 -6
  358. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +6 -6
  359. mage_ai/server/frontend_dist_base_path_template/index.html +3 -3
  360. mage_ai/server/frontend_dist_base_path_template/manage/files.html +6 -6
  361. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +6 -6
  362. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +6 -6
  363. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +6 -6
  364. mage_ai/server/frontend_dist_base_path_template/manage/users.html +6 -6
  365. mage_ai/server/frontend_dist_base_path_template/manage.html +6 -6
  366. mage_ai/server/frontend_dist_base_path_template/oauth.html +5 -5
  367. mage_ai/server/frontend_dist_base_path_template/overview.html +6 -6
  368. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +6 -6
  369. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  370. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +6 -6
  371. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +6 -6
  372. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +3 -3
  373. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +6 -6
  374. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  375. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  376. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +6 -6
  377. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +6 -6
  378. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +6 -6
  379. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +6 -6
  380. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +6 -6
  381. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  382. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +6 -6
  383. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +3 -3
  384. mage_ai/server/frontend_dist_base_path_template/pipelines.html +6 -6
  385. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +6 -6
  386. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +6 -6
  387. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +6 -6
  388. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +6 -6
  389. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +6 -6
  390. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +6 -6
  391. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +6 -6
  392. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +6 -6
  393. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +6 -6
  394. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +6 -6
  395. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +6 -6
  396. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +6 -6
  397. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +6 -6
  398. mage_ai/server/frontend_dist_base_path_template/settings.html +3 -3
  399. mage_ai/server/frontend_dist_base_path_template/sign-in.html +12 -12
  400. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +6 -6
  401. mage_ai/server/frontend_dist_base_path_template/templates.html +6 -6
  402. mage_ai/server/frontend_dist_base_path_template/terminal.html +6 -6
  403. mage_ai/server/frontend_dist_base_path_template/test.html +3 -3
  404. mage_ai/server/frontend_dist_base_path_template/triggers.html +6 -6
  405. mage_ai/server/frontend_dist_base_path_template/version-control.html +6 -6
  406. mage_ai/server/kernel_output_parser.py +4 -1
  407. mage_ai/server/scheduler_manager.py +9 -0
  408. mage_ai/server/server.py +35 -31
  409. mage_ai/server/utils/custom_output.py +284 -0
  410. mage_ai/server/utils/execute_custom_code.py +245 -0
  411. mage_ai/server/utils/output_display.py +123 -289
  412. mage_ai/server/websocket_server.py +116 -69
  413. mage_ai/services/k8s/config.py +23 -0
  414. mage_ai/services/k8s/job_manager.py +6 -1
  415. mage_ai/services/ssh/aws/emr/utils.py +8 -8
  416. mage_ai/settings/keys/auth.py +1 -0
  417. mage_ai/settings/platform/__init__.py +159 -38
  418. mage_ai/settings/platform/constants.py +5 -0
  419. mage_ai/settings/platform/utils.py +53 -10
  420. mage_ai/settings/repo.py +26 -12
  421. mage_ai/settings/server.py +128 -37
  422. mage_ai/shared/array.py +24 -1
  423. mage_ai/shared/complex.py +45 -0
  424. mage_ai/shared/config.py +2 -1
  425. mage_ai/shared/custom_logger.py +11 -0
  426. mage_ai/shared/dates.py +10 -6
  427. mage_ai/shared/files.py +63 -8
  428. mage_ai/shared/hash.py +33 -9
  429. mage_ai/shared/io.py +9 -5
  430. mage_ai/shared/models.py +82 -24
  431. mage_ai/shared/outputs.py +87 -0
  432. mage_ai/shared/parsers.py +141 -15
  433. mage_ai/shared/path_fixer.py +11 -7
  434. mage_ai/shared/singletons/__init__.py +0 -0
  435. mage_ai/shared/singletons/base.py +47 -0
  436. mage_ai/shared/singletons/memory.py +38 -0
  437. mage_ai/shared/strings.py +34 -1
  438. mage_ai/shared/yaml.py +24 -0
  439. mage_ai/streaming/sinks/oracledb.py +57 -0
  440. mage_ai/streaming/sinks/sink_factory.py +4 -0
  441. mage_ai/system/__init__.py +0 -0
  442. mage_ai/system/constants.py +14 -0
  443. mage_ai/system/memory/__init__.py +0 -0
  444. mage_ai/system/memory/constants.py +1 -0
  445. mage_ai/system/memory/manager.py +174 -0
  446. mage_ai/system/memory/presenters.py +158 -0
  447. mage_ai/system/memory/process.py +216 -0
  448. mage_ai/system/memory/samples.py +13 -0
  449. mage_ai/system/memory/utils.py +656 -0
  450. mage_ai/system/memory/wrappers.py +177 -0
  451. mage_ai/system/models.py +58 -0
  452. mage_ai/system/storage/__init__.py +0 -0
  453. mage_ai/system/storage/utils.py +29 -0
  454. mage_ai/tests/api/endpoints/mixins.py +2 -2
  455. mage_ai/tests/api/endpoints/test_blocks.py +2 -1
  456. mage_ai/tests/api/endpoints/test_custom_designs.py +4 -4
  457. mage_ai/tests/api/endpoints/test_pipeline_runs.py +2 -2
  458. mage_ai/tests/api/endpoints/test_projects.py +2 -1
  459. mage_ai/tests/api/operations/base/test_base.py +27 -27
  460. mage_ai/tests/api/operations/base/test_base_with_user_authentication.py +27 -27
  461. mage_ai/tests/api/operations/base/test_base_with_user_permissions.py +23 -23
  462. mage_ai/tests/api/operations/test_syncs.py +6 -4
  463. mage_ai/tests/api/resources/test_pipeline_resource.py +9 -2
  464. mage_ai/tests/authentication/providers/test_oidc.py +59 -0
  465. mage_ai/tests/base_test.py +2 -2
  466. mage_ai/tests/data/__init__.py +0 -0
  467. mage_ai/tests/data/models/__init__.py +0 -0
  468. mage_ai/tests/data_preparation/executors/test_block_executor.py +23 -16
  469. mage_ai/tests/data_preparation/git/test_git.py +4 -1
  470. mage_ai/tests/data_preparation/models/block/dynamic/test_combos.py +305 -0
  471. mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +212 -0
  472. mage_ai/tests/data_preparation/models/block/dynamic/test_factory.py +360 -0
  473. mage_ai/tests/data_preparation/models/block/dynamic/test_variables.py +332 -0
  474. mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +2 -2
  475. mage_ai/tests/data_preparation/models/block/platform/test_mixins.py +1 -1
  476. mage_ai/tests/data_preparation/models/block/sql/utils/test_shared.py +26 -1
  477. mage_ai/tests/data_preparation/models/block/test_global_data_product.py +3 -2
  478. mage_ai/tests/data_preparation/models/custom_templates/test_utils.py +5 -4
  479. mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +3 -0
  480. mage_ai/tests/data_preparation/models/global_hooks/test_predicates.py +9 -3
  481. mage_ai/tests/data_preparation/models/test_block.py +115 -120
  482. mage_ai/tests/data_preparation/models/test_blocks_helper.py +114 -0
  483. mage_ai/tests/data_preparation/models/test_global_data_product.py +41 -24
  484. mage_ai/tests/data_preparation/models/test_pipeline.py +9 -6
  485. mage_ai/tests/data_preparation/models/test_project.py +4 -1
  486. mage_ai/tests/data_preparation/models/test_utils.py +80 -0
  487. mage_ai/tests/data_preparation/models/test_variable.py +242 -69
  488. mage_ai/tests/data_preparation/models/variables/__init__.py +0 -0
  489. mage_ai/tests/data_preparation/models/variables/test_summarizer.py +481 -0
  490. mage_ai/tests/data_preparation/storage/shared/__init__.py +0 -0
  491. mage_ai/tests/data_preparation/test_repo_manager.py +6 -7
  492. mage_ai/tests/data_preparation/test_variable_manager.py +57 -48
  493. mage_ai/tests/factory.py +64 -43
  494. mage_ai/tests/orchestration/db/models/test_schedules.py +3 -3
  495. mage_ai/tests/orchestration/db/models/test_schedules_dynamic_blocks.py +279 -0
  496. mage_ai/tests/orchestration/test_pipeline_scheduler.py +1 -0
  497. mage_ai/tests/orchestration/triggers/test_global_data_product.py +3 -2
  498. mage_ai/tests/orchestration/triggers/test_utils.py +3 -2
  499. mage_ai/tests/services/k8s/test_job_manager.py +18 -0
  500. mage_ai/tests/streaming/sinks/test_oracledb.py +38 -0
  501. mage_ai/tests/test_shared.py +61 -0
  502. mage_ai/usage_statistics/logger.py +7 -2
  503. mage_ai/utils/code.py +33 -19
  504. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/METADATA +5 -2
  505. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/RECORD +513 -417
  506. mage_ai/data_preparation/models/global_data_product/constants.py +0 -6
  507. mage_ai/server/frontend_dist/_next/static/RhDiJSkcjCsh4xxX4BFBk/_buildManifest.js +0 -1
  508. mage_ai/server/frontend_dist/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
  509. mage_ai/server/frontend_dist/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
  510. mage_ai/server/frontend_dist/_next/static/chunks/4783-422429203610c318.js +0 -1
  511. mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
  512. mage_ai/server/frontend_dist/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
  513. mage_ai/server/frontend_dist/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
  514. mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
  515. mage_ai/server/frontend_dist/_next/static/chunks/7966-b9b85ba10667e654.js +0 -1
  516. mage_ai/server/frontend_dist/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
  517. mage_ai/server/frontend_dist/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
  518. mage_ai/server/frontend_dist/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
  519. mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
  520. mage_ai/server/frontend_dist/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
  521. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +0 -1
  522. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
  523. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
  524. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
  525. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +0 -1
  526. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
  527. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
  528. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
  529. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +0 -1
  530. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
  531. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +0 -1
  532. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +0 -1
  533. mage_ai/server/frontend_dist_base_path_template/_next/static/TdpLLFome13qvM0gXvpHs/_buildManifest.js +0 -1
  534. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
  535. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
  536. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4783-422429203610c318.js +0 -1
  537. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
  538. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
  539. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
  540. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
  541. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-b9b85ba10667e654.js +0 -1
  542. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
  543. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
  544. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
  545. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
  546. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
  547. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +0 -1
  548. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
  549. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
  550. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
  551. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +0 -1
  552. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
  553. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
  554. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
  555. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +0 -1
  556. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
  557. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +0 -1
  558. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +0 -1
  559. mage_ai/shared/memory.py +0 -90
  560. mage_ai/tests/data_preparation/models/block/dynamic/test_dynamic_helpers.py +0 -48
  561. /mage_ai/{tests/data_preparation/shared → ai/utils}/__init__.py +0 -0
  562. /mage_ai/server/frontend_dist/_next/static/{RhDiJSkcjCsh4xxX4BFBk → UZLabyPgcxtZvp0O0EUUS}/_ssgManifest.js +0 -0
  563. /mage_ai/server/frontend_dist_base_path_template/_next/static/{TdpLLFome13qvM0gXvpHs → kcptwoOU-JJJg6Vwpkfmx}/_ssgManifest.js +0 -0
  564. /mage_ai/tests/data_preparation/{shared → storage/shared}/test_secrets.py +0 -0
  565. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/LICENSE +0 -0
  566. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/WHEEL +0 -0
  567. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/entry_points.txt +0 -0
  568. {mage_ai-0.9.70.dist-info → mage_ai-0.9.71.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,50 @@
1
+ """
2
+ If you add a new environment variable, make sure to check if it should be added to
3
+ the `MAGE_SETTINGS_ENVIRONMENT_VARIABLES` list at the bottom of this file. Also, update
4
+ the environment variable documentation at docs/development/variables/environment-variables.mdx
5
+ """
6
+
1
7
  import os
2
8
 
3
9
  from .secret_generation import generate_jwt_secret
4
10
 
5
- # If you add a new environment variable, make sure to check if it should be added to
6
- # the `MAGE_SETTINGS_ENVIRONMENT_VARIABLES` list at the bottom of this file. Also, update
7
- # the environment variable documentation at docs/development/variables/environment-variables.mdx
11
+
12
+ def get_bool_value(value: str) -> bool:
13
+ """
14
+ Helper method to get the boolean value from a string.
15
+
16
+ Converts a string environment variable to a bool value. Returns True if the value
17
+ is 'true', '1', or 't' (case insensitive). Otherwise, False
18
+ """
19
+ if value is None:
20
+ return False
21
+
22
+ return value.lower() in ('true', '1', 't')
23
+
24
+
25
+ def get_int_value(value: str) -> int:
26
+ if not value:
27
+ return None
28
+ try:
29
+ int_value = int(value)
30
+ except Exception:
31
+ int_value = None
32
+ return int_value
33
+
34
+
35
+ # ----------------------------------
36
+ # Debugging and Environment Settings
37
+ # ----------------------------------
8
38
 
9
39
  DEBUG = os.getenv('DEBUG', False)
40
+ DEBUG_MEMORY = str(os.getenv('DEBUG_MEMORY', 0) or 0) in ['1', 'true', 'True']
41
+ DEBUG_FILE_IO = str(os.getenv('DEBUG_FILE_IO', 0) or 0) in ['1', 'true', 'True']
10
42
  HIDE_ENV_VAR_VALUES = int(os.getenv('HIDE_ENV_VAR_VALUES', 1) or 1) == 1
11
- QUERY_API_KEY = 'api_key'
43
+
44
+
45
+ # -------------------------
46
+ # Server Authentication and Token Settings
47
+ # -------------------------
12
48
 
13
49
  """
14
50
  import secrets
@@ -18,6 +54,18 @@ Make sure this value is the same in mage_ai/frontend/api/constants.ts
18
54
  """
19
55
  OAUTH2_APPLICATION_CLIENT_ID = 'zkWlN0PkIKSN0C11CfUHUj84OT5XOJ6tDZ6bDRO2'
20
56
 
57
+ QUERY_API_KEY = 'api_key'
58
+
59
+ # Used for OAUTH
60
+ JWT_SECRET = os.getenv('JWT_SECRET', 'materia')
61
+ # Used for generating download tokens
62
+ JWT_DOWNLOAD_SECRET = os.getenv('JWT_DOWNLOAD_SECRET', generate_jwt_secret())
63
+
64
+
65
+ # -------------------------
66
+ # Notebook and Terminal Edit Access
67
+ # -------------------------
68
+
21
69
  # valid values: 0, 1, 2
22
70
  try:
23
71
  DISABLE_NOTEBOOK_EDIT_ACCESS = int(os.getenv('DISABLE_NOTEBOOK_EDIT_ACCESS', 0))
@@ -25,6 +73,9 @@ except ValueError:
25
73
  DISABLE_NOTEBOOK_EDIT_ACCESS = 1 if os.getenv('DISABLE_NOTEBOOK_EDIT_ACCESS') else 0
26
74
 
27
75
 
76
+ DISABLE_TERMINAL = get_bool_value(os.getenv('DISABLE_TERMINAL', '0').lower())
77
+
78
+
28
79
  def is_disable_pipeline_edit_access(
29
80
  disable_notebook_edit_access_override: int = None,
30
81
  ) -> bool:
@@ -34,33 +85,22 @@ def is_disable_pipeline_edit_access(
34
85
  return value >= 1
35
86
 
36
87
 
37
- def get_bool_value(value: str) -> bool:
38
- """
39
- Converts a string environment variable to a bool value. Returns True if the value
40
- is 'true', '1', or 't' (case insensitive). Otherwise, False
41
- """
42
- if value is None:
43
- return False
44
-
45
- return value.lower() in ('true', '1', 't')
46
-
47
-
48
- # ------------------------- DISABLE TERMINAL ----------------------
88
+ # Limit the image preview size to 5MBs by default. If a block returns an XBoost model
89
+ # (e.g.) xgboost.Booster() instance, the preview in the UI is a tree plot of the model.
90
+ # The image can be very large in byte size, so we limit the size to prevent the UI from freezing.
91
+ MAX_OUTPUT_IMAGE_PREVIEW_SIZE = int(os.getenv('MAX_OUTPUT_IMAGE_PREVIEW_SIZE', 1024 * 1024 * 5))
49
92
 
50
- DISABLE_TERMINAL = os.getenv('DISABLE_TERMINAL', '0').lower() in ('true', '1', 't')
93
+ # -------------------
94
+ # User Authentication Settings
95
+ # -------------------
51
96
 
52
- # ----------------- Authentication settings ----------------
53
- REQUIRE_USER_AUTHENTICATION = get_bool_value(
54
- os.getenv('REQUIRE_USER_AUTHENTICATION', 'False')
55
- )
97
+ REQUIRE_USER_AUTHENTICATION = get_bool_value(os.getenv('REQUIRE_USER_AUTHENTICATION', 'False'))
56
98
  REQUIRE_USER_PERMISSIONS = REQUIRE_USER_AUTHENTICATION and get_bool_value(
57
99
  os.getenv('REQUIRE_USER_PERMISSIONS', 'False')
58
100
  )
59
101
  AUTHENTICATION_MODE = os.getenv('AUTHENTICATION_MODE', 'LOCAL')
60
102
  try:
61
- MAGE_ACCESS_TOKEN_EXPIRY_TIME = int(
62
- os.getenv('MAGE_ACCESS_TOKEN_EXPIRY_TIME', '2592000')
63
- )
103
+ MAGE_ACCESS_TOKEN_EXPIRY_TIME = int(os.getenv('MAGE_ACCESS_TOKEN_EXPIRY_TIME', '2592000'))
64
104
  except ValueError:
65
105
  MAGE_ACCESS_TOKEN_EXPIRY_TIME = 2592000
66
106
 
@@ -68,9 +108,22 @@ except ValueError:
68
108
  # for the first time. value should be the name of a Mage role (e.g. Viewer, Editor, Admin)
69
109
  OAUTH_DEFAULT_ACCESS = os.getenv('OAUTH_DEFAULT_ACCESS')
70
110
 
71
- # ----------------------------------------------------------
72
111
 
112
+ # ---------------------
113
+ # General Server Settings
114
+ # ---------------------
115
+ CONCURRENCY_CONFIG_BLOCK_RUN_LIMIT = get_int_value(os.getenv('CONCURRENCY_CONFIG_BLOCK_RUN_LIMIT'))
116
+ CONCURRENCY_CONFIG_PIPELINE_RUN_LIMIT = get_int_value(
117
+ os.getenv('CONCURRENCY_CONFIG_PIPELINE_RUN_LIMIT')
118
+ )
119
+ DISABLE_AUTO_BROWSER_OPEN = get_bool_value(os.getenv('DISABLE_AUTO_BROWSER_OPEN', 'False'))
120
+ DISABLE_AUTORELOAD = get_bool_value(os.getenv('DISABLE_AUTORELOAD', 'False'))
121
+ # The hostname in Kubernetes or AWS ECS
73
122
  HOSTNAME = os.getenv('HOSTNAME')
123
+ INITIAL_METADATA = os.getenv('INITIAL_METADATA')
124
+ LOGS_DIR_PATH = os.getenv('LOGS_DIR_PATH')
125
+ MAX_FILE_CACHE_SIZE = os.getenv('MAX_FILE_CACHE_SIZE') or (1024 * 1024) # 1 MB
126
+ ENABLE_USER_PROJECTS = get_bool_value(os.getenv('ENABLE_USER_PROJECTS'))
74
127
  REDIS_URL = os.getenv('REDIS_URL')
75
128
  SERVER_VERBOSITY = os.getenv('SERVER_VERBOSITY', 'info') or 'info'
76
129
  SERVER_LOGGING_FORMAT = os.getenv('SERVER_LOGGING_FORMAT', 'plaintext')
@@ -79,36 +132,49 @@ SERVER_LOGGING_TEMPLATE = os.getenv(
79
132
  '%(levelname)s:%(name)s:%(message)s',
80
133
  )
81
134
 
82
- INITIAL_METADATA = os.getenv('INITIAL_METADATA')
83
135
 
84
- DISABLE_AUTO_BROWSER_OPEN = get_bool_value(os.getenv('DISABLE_AUTO_BROWSER_OPEN', 'False'))
136
+ # --------------------
137
+ # Shell Settings
138
+ # --------------------
85
139
 
86
140
  SHELL_COMMAND = os.getenv('SHELL_COMMAND', None)
87
141
  USE_UNIQUE_TERMINAL = os.getenv('USE_UNIQUE_TERMINAL', None)
88
142
 
89
- # sentry environment variables
143
+
144
+ # -------------------------
145
+ # Monitoring and Tracing Configuration
146
+ # -------------------------
147
+
148
+ # Sentry Configuration
90
149
  SENTRY_DSN = os.getenv('SENTRY_DSN')
91
150
  SENTRY_TRACES_SAMPLE_RATE = os.getenv('SENTRY_TRACES_SAMPLE_RATE', 1.0)
92
151
 
93
- # New relic enable environment variable
152
+ # New Relic Configuration
94
153
  ENABLE_NEW_RELIC = os.getenv('ENABLE_NEW_RELIC', False)
95
154
  NEW_RELIC_CONFIG_PATH = os.getenv('NEW_RELIC_CONFIG_PATH', '')
96
155
 
156
+ # Prometheus Configuration
97
157
  # If enabled, the /metrics route will expose Tornado server metrics
98
158
  ENABLE_PROMETHEUS = get_bool_value(os.getenv('ENABLE_PROMETHEUS', 'False'))
99
159
 
100
- # OpenTelemetry configuration
160
+ # OpenTelemetry Configuration
101
161
  OTEL_EXPORTER_OTLP_ENDPOINT = os.getenv('OTEL_EXPORTER_OTLP_ENDPOINT', None)
102
162
  OTEL_EXPORTER_OTLP_HTTP_ENDPOINT = os.getenv('OTEL_EXPORTER_HTTP_OTLP_ENDPOINT', None)
103
163
  OTEL_PYTHON_TORNADO_EXCLUDED_URLS = (
104
164
  os.getenv('OTEL_PYTHON_TORNADO_EXCLUDED_URLS') or '/api/statuses'
105
165
  )
106
166
 
107
- DEFAULT_LOCALHOST_URL = 'http://localhost:6789'
108
- MAGE_PUBLIC_HOST = os.getenv('MAGE_PUBLIC_HOST') or DEFAULT_LOCALHOST_URL
167
+ SYSTEM_LOGS_PARTITIONS = [
168
+ str(partition).strip() for partition in os.getenv('SYSTEM_LOGS_PARTITIONS', 'ds').split(',')
169
+ ]
170
+ SYSTEM_LOGS_POLL_INTERVAL = float(os.getenv('SYSTEM_LOGS_POLL_INTERVAL', 0.1))
109
171
 
110
- MAX_FILE_CACHE_SIZE = os.getenv('MAX_FILE_CACHE_SIZE') or (1024 * 1024) # 1 MB
172
+ # -----------------------------
173
+ # Mage URL and PATH Settings
174
+ # -----------------------------
111
175
 
176
+ DEFAULT_LOCALHOST_URL = 'http://localhost:6789'
177
+ MAGE_PUBLIC_HOST = os.getenv('MAGE_PUBLIC_HOST') or DEFAULT_LOCALHOST_URL
112
178
  # All base path variables should not include a leading forward slash
113
179
  # e.g. MAGE_BASE_PATH = 'test_prefix' -> localhost:6789/test_prefix/pipelines
114
180
  BASE_PATH = os.getenv('MAGE_BASE_PATH')
@@ -118,10 +184,12 @@ REQUESTS_BASE_PATH = os.getenv('MAGE_REQUESTS_BASE_PATH', BASE_PATH)
118
184
  # Routes base path is used to configure the base path for the backend routes. Defaults
119
185
  # to the MAGE_BASE_PATH environment variable.
120
186
  ROUTES_BASE_PATH = os.getenv('MAGE_ROUTES_BASE_PATH', BASE_PATH)
121
- # Used for OAUTH
122
- JWT_SECRET = os.getenv('JWT_SECRET', 'materia')
123
- # Used for generating download tokens
124
- JWT_DOWNLOAD_SECRET = os.getenv('JWT_DOWNLOAD_SECRET', generate_jwt_secret())
187
+
188
+
189
+ # -------------------------
190
+ # Scheduler Settings
191
+ # -------------------------
192
+
125
193
  # Sets the trigger interval of the scheduler to a numeric value, in seconds
126
194
  # Determines how often the scheduler gets invoked
127
195
  try:
@@ -129,11 +197,32 @@ try:
129
197
  except ValueError:
130
198
  SCHEDULER_TRIGGER_INTERVAL = 10
131
199
 
200
+ # -------------------------
201
+ # System level features
202
+ # -------------------------
203
+ # We need to use os.getenv again or else we can’t mock/patch the value in tests.
204
+ DYNAMIC_BLOCKS_VERSION = int(os.getenv('DYNAMIC_BLOCKS_VERSION') or 1)
205
+ DYNAMIC_BLOCKS_V2 = int(os.getenv('DYNAMIC_BLOCKS_VERSION') or 1) >= 2
206
+ MEMORY_MANAGER_VERSION = int(os.getenv('MEMORY_MANAGER_VERSION') or 1)
207
+ MEMORY_MANAGER_V2 = int(os.getenv('MEMORY_MANAGER_VERSION') or 1) >= 2
208
+ MEMORY_MANAGER_PANDAS_VERSION = int(os.getenv('MEMORY_MANAGER_PANDAS_VERSION') or 1)
209
+ MEMORY_MANAGER_POLARS_VERSION = int(os.getenv('MEMORY_MANAGER_POLARS_VERSION') or 1)
210
+ MEMORY_MANAGER_PANDAS_V2 = int(os.getenv('MEMORY_MANAGER_PANDAS_VERSION') or 1) >= 2
211
+ MEMORY_MANAGER_POLARS_V2 = int(os.getenv('MEMORY_MANAGER_POLARS_VERSION') or 1) >= 2
212
+ VARIABLE_DATA_OUTPUT_META_CACHE = str(os.getenv('VARIABLE_DATA_OUTPUT_META_CACHE', 0) or 0) in [
213
+ '1',
214
+ 'true',
215
+ 'True',
216
+ ]
217
+
132
218
  # List of environment variables used to configure Mage. The value of these settings
133
219
  # will be copied between workspaces.
134
220
  MAGE_SETTINGS_ENVIRONMENT_VARIABLES = [
221
+ 'CONCURRENCY_CONFIG_BLOCK_RUN_LIMIT',
222
+ 'CONCURRENCY_CONFIG_PIPELINE_RUN_LIMIT',
135
223
  'DISABLE_NOTEBOOK_EDIT_ACCESS',
136
224
  'DISABLE_AUTO_BROWSER_OPEN',
225
+ 'DISABLE_AUTORELOAD',
137
226
  'REQUIRE_USER_AUTHENTICATION',
138
227
  'AUTHENTICATION_MODE',
139
228
  'OAUTH_DEFAULT_ACCESS',
@@ -174,6 +263,7 @@ MAGE_SETTINGS_ENVIRONMENT_VARIABLES = [
174
263
  'OIDC_CLIENT_ID',
175
264
  'OIDC_CLIENT_SECRET',
176
265
  'OIDC_DISCOVERY_URL',
266
+ 'OIDC_ROLES_MAPPING',
177
267
  'GHE_CLIENT_ID',
178
268
  'GHE_CLIENT_SECRET',
179
269
  'GHE_HOSTNAME',
@@ -184,4 +274,5 @@ MAGE_SETTINGS_ENVIRONMENT_VARIABLES = [
184
274
  'GITLAB_CLIENT_ID',
185
275
  'GITLAB_CLIENT_SECRET',
186
276
  'SERVER_LOGGING_TEMPLATE',
277
+ 'MAX_OUTPUT_IMAGE_PREVIEW_SIZE',
187
278
  ]
mage_ai/shared/array.py CHANGED
@@ -1,10 +1,12 @@
1
1
  import random
2
+ from collections.abc import Iterable
3
+ from typing import Any
2
4
 
3
5
 
4
6
  def batch(iterable, n=1):
5
7
  length = len(iterable)
6
8
  for ndx in range(0, length, n):
7
- yield iterable[ndx:min(ndx + n, length)]
9
+ yield iterable[ndx: min(ndx + n, length)]
8
10
 
9
11
 
10
12
  def difference(li1, li2):
@@ -50,3 +52,24 @@ def unique_by(arr1, key):
50
52
  arr2.append(item)
51
53
  mapping[k] = True
52
54
  return arr2
55
+
56
+
57
+ def is_iterable(
58
+ obj: Any, exclude_dicts: bool = True, exclude_strings: bool = True
59
+ ) -> bool:
60
+ """
61
+ Check if an object is iterable, optionally excluding strings.
62
+
63
+ Args:
64
+ obj: The object to check for iterability.
65
+ exclude_strings (bool): Whether to consider strings as non-iterable (to exclude them).
66
+
67
+ Returns:
68
+ bool: True if the object is iterable; False otherwise.
69
+ """
70
+ if (exclude_strings and isinstance(obj, str)) or (
71
+ exclude_dicts and isinstance(obj, dict)
72
+ ):
73
+ return False
74
+
75
+ return isinstance(obj, Iterable)
@@ -0,0 +1,45 @@
1
+ import inspect
2
+ from typing import Any
3
+
4
+
5
+ def is_model_sklearn(data: Any) -> bool:
6
+ if inspect.isclass(data):
7
+ return False
8
+
9
+ try:
10
+ from sklearn.base import BaseEstimator, is_classifier, is_regressor
11
+
12
+ return (
13
+ is_classifier(data) or is_regressor(data) or isinstance(data, BaseEstimator)
14
+ )
15
+ except ImportError as err:
16
+ print(f"Error importing sklearn: {err}")
17
+ return False
18
+
19
+
20
+ def is_model_xgboost(data: Any) -> bool:
21
+ """
22
+ Checks if the given data is an instance of an XGBoost model, either a Booster
23
+ or an object from XGBoost's scikit-learn API.
24
+ """
25
+ if inspect.isclass(data):
26
+ return False
27
+
28
+ # Check for direct instance of Booster
29
+ if inspect.isclass(data):
30
+ # Checking if it's a class reference rather than an instance
31
+ if "xgboost.core.Booster" == f"{data.__module__}.{data.__qualname__}":
32
+ return True
33
+ else:
34
+ # Check based on instance attributes and methods
35
+ if hasattr(data, "__class__"):
36
+ class_name = f"{data.__class__.__module__}.{data.__class__.__qualname__}"
37
+ if class_name.startswith("xgboost.core.Booster"):
38
+ return True
39
+
40
+ # Check for sklearn API models (like XGBClassifier, XGBRegressor)
41
+ # These models have a get_booster() method
42
+ if hasattr(data, "get_booster"):
43
+ return True
44
+
45
+ return False
mage_ai/shared/config.py CHANGED
@@ -7,6 +7,7 @@ import yaml
7
7
 
8
8
  from mage_ai.shared.hash import merge_dict
9
9
  from mage_ai.shared.strings import camel_to_snake_case
10
+ from mage_ai.shared.yaml import load_yaml
10
11
 
11
12
 
12
13
  @dataclass
@@ -77,7 +78,7 @@ class BaseConfig:
77
78
 
78
79
  try:
79
80
  with open(config_path, 'r') as stream:
80
- file_config = yaml.load(stream, Loader=yaml.SafeLoader)
81
+ file_config = load_yaml(stream)
81
82
  return merge_dict(config, file_config)
82
83
  except yaml.YAMLError as e:
83
84
  print(e)
@@ -150,6 +150,17 @@ class ColorPrinter:
150
150
  __uuid='get_callers'
151
151
  )
152
152
 
153
+ def print_call_stack(self):
154
+ stack = inspect.stack()
155
+ stack_list = []
156
+ for frame_info in stack:
157
+ frame = frame_info.frame
158
+ filename = frame.f_code.co_filename
159
+ lineno = frame.f_lineno
160
+ function_name = frame.f_code.co_name
161
+ stack_list.append(f"File '{filename}', line {lineno}, in {function_name}")
162
+ self.info('Call stack:', stack=stack_list)
163
+
153
164
 
154
165
  class CustomFormatter(logging.Formatter):
155
166
  # https://stackoverflow.com/a/56944256/1084284
mage_ai/shared/dates.py CHANGED
@@ -1,10 +1,12 @@
1
1
  import datetime
2
+ from typing import List, Optional, Tuple
3
+
2
4
  import pytz
3
5
 
4
6
  from mage_ai.shared.array import find_index
5
7
 
6
8
 
7
- def compare(date1: datetime, date2: datetime) -> int:
9
+ def compare(date1, date2) -> Optional[int]:
8
10
  if date1 is None or date2 is None:
9
11
  return None
10
12
 
@@ -27,8 +29,7 @@ def n_days_ago(n: int) -> str:
27
29
  def str_to_timedelta(period_str: str):
28
30
  unit = period_str[-1]
29
31
  if unit not in ['d', 'h', 'w']:
30
- raise Exception(
31
- 'Please provide a valid period unit ("d", "h", or "w")')
32
+ raise Exception('Please provide a valid period unit ("d", "h", or "w")')
32
33
  if unit == 'd':
33
34
  return datetime.timedelta(days=int(period_str[:-1]))
34
35
  elif unit == 'h':
@@ -45,8 +46,8 @@ def week_of_month(day: datetime.datetime) -> int:
45
46
 
46
47
  # e.g. 7 - 5 = 2
47
48
  first_week_last_day = 7 - ((first_day_weekday + 1) % 7)
48
- day_ranges_per_week = [
49
- # If the 1st day is Friday, then Saturday is the 2nd, and that is the end of the 1st week
49
+ # If the 1st day is Friday, then Saturday is the 2nd, and that is the end of the 1st week
50
+ day_ranges_per_week: List[Tuple[int, int]] = [
50
51
  (1, first_week_last_day),
51
52
  ]
52
53
 
@@ -57,7 +58,10 @@ def week_of_month(day: datetime.datetime) -> int:
57
58
  # 3: (24, 30)
58
59
  # 4: (31, 37)
59
60
  day_ranges_per_week.append(
60
- (first_week_last_day + 1 + (7 * i), first_week_last_day + (7 * (i + 1))),
61
+ (
62
+ first_week_last_day + 1 + (7 * i),
63
+ first_week_last_day + (7 * (i + 1)),
64
+ ),
61
65
  )
62
66
 
63
67
  # If the first day of the month is a Friday, here are the day ranges for each week:
mage_ai/shared/files.py CHANGED
@@ -1,5 +1,8 @@
1
+ import asyncio
1
2
  import glob
2
3
  import os
4
+ import shutil
5
+ import time
3
6
  from pathlib import Path
4
7
  from typing import Callable, Dict, List, Tuple
5
8
 
@@ -55,10 +58,15 @@ def read_last_line(filename: str) -> str:
55
58
 
56
59
 
57
60
  def get_full_file_paths_containing_item(root_full_path: str, comparator: Callable) -> List[str]:
58
- configfiles = [os.path.join(
59
- dirpath,
60
- f,
61
- ) for dirpath, dirnames, files in os.walk(root_full_path) for f in files if comparator(f)]
61
+ configfiles = [
62
+ os.path.join(
63
+ dirpath,
64
+ f,
65
+ )
66
+ for dirpath, dirnames, files in os.walk(root_full_path)
67
+ for f in files
68
+ if comparator(f)
69
+ ]
62
70
 
63
71
  return configfiles
64
72
 
@@ -101,10 +109,11 @@ def get_absolute_paths_from_all_files(
101
109
  for filename in glob.iglob(dir_path, recursive=True):
102
110
  absolute_path = os.path.abspath(filename)
103
111
 
104
- if os.path.isfile(absolute_path) and \
105
- (not include_hidden_files or not absolute_path.startswith('.')) and \
106
- (not comparator or comparator(absolute_path)):
107
-
112
+ if (
113
+ os.path.isfile(absolute_path)
114
+ and (not include_hidden_files or not absolute_path.startswith('.'))
115
+ and (not comparator or comparator(absolute_path))
116
+ ):
108
117
  value = (absolute_path, os.path.getsize(filename), round(os.path.getmtime(filename)))
109
118
  arr.append(parse_values(value) if parse_values else value)
110
119
 
@@ -149,3 +158,49 @@ async def read_async(file_path: str) -> str:
149
158
  except Exception as err:
150
159
  if is_debug():
151
160
  print(f'[ERROR] files.read_async: {err}.')
161
+
162
+
163
+ def safe_delete_dir_sync(output_dir, verbose: bool = False):
164
+ max_attempts = 5
165
+ for attempt in range(max_attempts):
166
+ try:
167
+ shutil.rmtree(output_dir)
168
+ if verbose:
169
+ print(f'Successfully deleted {output_dir}')
170
+ break # Successfully deleted; exit the loop
171
+ except OSError as err:
172
+ if attempt < max_attempts - 1:
173
+ time.sleep(2) # Wait a bit for retry
174
+ continue
175
+ else:
176
+ print(f'Failed to delete {output_dir} after {max_attempts} attempts: {err}')
177
+ raise err
178
+
179
+
180
+ async def safe_delete_dir_async(output_dir: str, verbose: bool = False):
181
+ loop = asyncio.get_event_loop()
182
+ max_attempts = 5
183
+
184
+ for attempt in range(max_attempts):
185
+ try:
186
+ await loop.run_in_executor(None, shutil.rmtree, output_dir)
187
+ if verbose:
188
+ print(f'Successfully deleted {output_dir}')
189
+ break # Successfully deleted; exit the loop
190
+ except OSError as err:
191
+ # Handles the potential need for retry due to file locking/availability/etc.
192
+ if attempt < max_attempts - 1:
193
+ await asyncio.sleep(2) # Non-blocking wait before retry
194
+ continue
195
+ else:
196
+ print(f'Failed to delete {output_dir} after {max_attempts} attempts: {err}')
197
+ raise
198
+
199
+
200
+ def makedirs_sync(path: str):
201
+ os.makedirs(path, exist_ok=True)
202
+
203
+
204
+ async def makedirs_async(path: str):
205
+ loop = asyncio.get_running_loop()
206
+ await loop.run_in_executor(None, os.makedirs, path, exist_ok=True)
mage_ai/shared/hash.py CHANGED
@@ -23,11 +23,11 @@ def camel_case_keys_to_snake_case(d):
23
23
 
24
24
  def dig(obj_arg, arr_or_string):
25
25
  if type(arr_or_string) is str:
26
- arr_or_string = arr_or_string.split('.')
26
+ arr_or_string = arr_or_string.split(".")
27
27
  arr = list(map(str.strip, arr_or_string))
28
28
 
29
29
  def _build(obj, key):
30
- tup = re.split(r'\[(\d+)\]$', key)
30
+ tup = re.split(r"\[(\d+)\]$", key)
31
31
  if len(tup) >= 2:
32
32
  key, index = filter(lambda x: x, tup)
33
33
  if key and index:
@@ -56,7 +56,7 @@ def safe_dig(obj_arg, arr_or_string):
56
56
  key/index is missing or the object is None.
57
57
  """
58
58
  if isinstance(arr_or_string, str):
59
- arr_or_string = arr_or_string.split('.')
59
+ arr_or_string = arr_or_string.split(".")
60
60
  arr = list(map(str.strip, arr_or_string))
61
61
 
62
62
  def _build(obj, key):
@@ -64,7 +64,7 @@ def safe_dig(obj_arg, arr_or_string):
64
64
  if obj is None or not isinstance(obj, dict) and not isinstance(obj, list):
65
65
  return None
66
66
 
67
- tup = re.split(r'\[(\d+)\]$', key)
67
+ tup = re.split(r"\[(\d+)\]$", key)
68
68
  if len(tup) >= 2:
69
69
  key, index = filter(lambda x: x, tup)
70
70
  index = int(index) if index else None
@@ -96,15 +96,39 @@ def flatten(input_data):
96
96
  for k2, v2 in v1.items():
97
97
  if type(v2) is dict:
98
98
  for k3, v3 in v2.items():
99
- final_data[f'{k1}_{k2}_{k3}'] = v3
99
+ final_data[f"{k1}_{k2}_{k3}"] = v3
100
100
  else:
101
- final_data[f'{k1}_{k2}'] = v2
101
+ final_data[f"{k1}_{k2}"] = v2
102
102
  else:
103
103
  final_data[k1] = v1
104
104
 
105
105
  return final_data
106
106
 
107
107
 
108
+ def flatten_dict(d, parent_key="", sep="."):
109
+ items = []
110
+ for k, v in d.items():
111
+ new_key = f"{parent_key}{sep}{k}" if parent_key else k
112
+ if isinstance(v, dict):
113
+ items.extend(flatten_dict(v, new_key, sep=sep).items())
114
+ else:
115
+ items.append((new_key, v))
116
+ return dict(items)
117
+
118
+
119
+ def unflatten_dict(d, sep="."):
120
+ result_dict = {}
121
+ for k, v in d.items():
122
+ parts = k.split(sep)
123
+ current_level = result_dict
124
+ for part in parts[:-1]:
125
+ if part not in current_level:
126
+ current_level[part] = {}
127
+ current_level = current_level[part]
128
+ current_level[parts[-1]] = v
129
+ return result_dict
130
+
131
+
108
132
  def get_json_value(str_value, arr_or_string):
109
133
  if not str_value:
110
134
  return str_value
@@ -207,11 +231,11 @@ def set_value(obj: Dict, keys: List[str], value) -> Dict:
207
231
 
208
232
  results = dict(__obj_to_set_value=obj, __value=value)
209
233
 
210
- key = ''.join(f"['{key}']" for key in keys)
211
- expression = f'__obj_to_set_value{key} = __value'
234
+ key = "".join(f"['{key}']" for key in keys)
235
+ expression = f"__obj_to_set_value{key} = __value"
212
236
  exec(expression, results)
213
237
 
214
- return results['__obj_to_set_value']
238
+ return results["__obj_to_set_value"]
215
239
 
216
240
 
217
241
  def combine_into(child: Dict, parent: Dict) -> None:
mage_ai/shared/io.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import shutil
3
3
  import traceback
4
- from typing import Callable, Union
4
+ from typing import Callable, Optional, Union
5
5
 
6
6
  import aiofiles
7
7
 
@@ -29,7 +29,9 @@ def chmod(path: Union[str, os.PathLike], mode: int, append: bool = True) -> None
29
29
  traceback.print_exc()
30
30
 
31
31
 
32
- def safe_write(filepath: str, content: str, write_func: Callable = None):
32
+ def safe_write(
33
+ filepath: str, content: str, write_func: Optional[Callable] = None, write_mode: str = 'w'
34
+ ):
33
35
  temp_file_path = filepath + '.temp'
34
36
  if os.path.isfile(filepath):
35
37
  shutil.copy2(filepath, temp_file_path)
@@ -39,7 +41,7 @@ def safe_write(filepath: str, content: str, write_func: Callable = None):
39
41
 
40
42
  success = False
41
43
  try:
42
- with open(filepath, 'w', encoding='utf-8') as fp:
44
+ with open(filepath, write_mode, encoding='utf-8') as fp:
43
45
  if write_func is not None:
44
46
  write_func(fp, content)
45
47
  else:
@@ -57,7 +59,9 @@ def safe_write(filepath: str, content: str, write_func: Callable = None):
57
59
  traceback.print_exc()
58
60
 
59
61
 
60
- async def safe_write_async(filepath: str, content: str, write_func: Callable = None):
62
+ async def safe_write_async(
63
+ filepath: str, content: str, write_func: Optional[Callable] = None, write_mode: str = 'w'
64
+ ):
61
65
  temp_file_path = filepath + '.temp'
62
66
  if os.path.isfile(filepath):
63
67
  shutil.copy2(filepath, temp_file_path)
@@ -67,7 +71,7 @@ async def safe_write_async(filepath: str, content: str, write_func: Callable = N
67
71
 
68
72
  success = False
69
73
  try:
70
- async with aiofiles.open(filepath, mode='w', encoding='utf-8') as fp:
74
+ async with aiofiles.open(filepath, mode=write_mode, encoding='utf-8') as fp:
71
75
  if write_func is not None:
72
76
  await write_func(fp, content)
73
77
  else: