mage-ai 0.9.74__py3-none-any.whl → 0.9.79__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.
Files changed (420) hide show
  1. mage_ai/ai/llm_pipeline_wizard.py +6 -4
  2. mage_ai/ai/openai_client.py +7 -5
  3. mage_ai/api/policies/PipelineSchedulePolicy.py +1 -0
  4. mage_ai/api/presenters/PipelineSchedulePresenter.py +11 -2
  5. mage_ai/api/resources/GitFileResource.py +8 -0
  6. mage_ai/api/resources/PipelineScheduleResource.py +20 -14
  7. mage_ai/api/resources/PipelineTriggerResource.py +3 -1
  8. mage_ai/api/resources/SessionResource.py +2 -2
  9. mage_ai/api/resources/SyncResource.py +1 -1
  10. mage_ai/api/resources/UserResource.py +1 -1
  11. mage_ai/cli/main.py +8 -1
  12. mage_ai/data_cleaner/analysis/charts.py +1 -1
  13. mage_ai/data_cleaner/cleaning_rules/reformat_values.py +1 -1
  14. mage_ai/data_integrations/destinations/constants.py +3 -0
  15. mage_ai/data_integrations/sources/constants.py +2 -0
  16. mage_ai/data_preparation/executors/block_executor.py +8 -3
  17. mage_ai/data_preparation/executors/pipeline_executor.py +35 -19
  18. mage_ai/data_preparation/git/utils.py +2 -2
  19. mage_ai/data_preparation/logging/logger_manager.py +31 -2
  20. mage_ai/data_preparation/models/block/__init__.py +33 -27
  21. mage_ai/data_preparation/models/block/dbt/dbt_adapter.py +20 -8
  22. mage_ai/data_preparation/models/block/dynamic/constants.py +0 -1
  23. mage_ai/data_preparation/models/block/dynamic/counter.py +1 -3
  24. mage_ai/data_preparation/models/block/outputs.py +7 -1
  25. mage_ai/data_preparation/models/block/r/__init__.py +16 -5
  26. mage_ai/data_preparation/models/block/sql/__init__.py +2 -0
  27. mage_ai/data_preparation/models/block/sql/mssql.py +8 -0
  28. mage_ai/data_preparation/models/block/sql/utils/shared.py +6 -2
  29. mage_ai/data_preparation/models/constants.py +4 -1
  30. mage_ai/data_preparation/models/pipeline.py +11 -2
  31. mage_ai/data_preparation/models/project/__init__.py +3 -1
  32. mage_ai/data_preparation/models/triggers/__init__.py +1 -1
  33. mage_ai/data_preparation/storage/local_storage.py +4 -1
  34. mage_ai/data_preparation/templates/constants.py +7 -0
  35. mage_ai/data_preparation/templates/data_exporters/streaming/elasticsearch.yaml +3 -0
  36. mage_ai/data_preparation/templates/data_loaders/airtable.py +28 -0
  37. mage_ai/data_preparation/templates/data_loaders/streaming/nats.yaml +6 -3
  38. mage_ai/data_preparation/templates/repo/io_config.yaml +2 -0
  39. mage_ai/io/airtable.py +104 -0
  40. mage_ai/io/base.py +30 -1
  41. mage_ai/io/bigquery.py +36 -0
  42. mage_ai/io/config.py +6 -0
  43. mage_ai/io/mssql.py +21 -9
  44. mage_ai/io/mysql.py +6 -1
  45. mage_ai/io/oracledb.py +2 -4
  46. mage_ai/io/postgres.py +41 -19
  47. mage_ai/io/qdrant.py +1 -1
  48. mage_ai/io/redshift.py +13 -0
  49. mage_ai/io/sql.py +1 -0
  50. mage_ai/io/utils.py +18 -0
  51. mage_ai/orchestration/db/__init__.py +23 -3
  52. mage_ai/orchestration/db/migrations/versions/39d36f1dab73_create_genericjob.py +47 -0
  53. mage_ai/orchestration/db/models/oauth.py +2 -1
  54. mage_ai/orchestration/db/models/schedules.py +108 -6
  55. mage_ai/orchestration/db/models/schedules_project_platform.py +1 -1
  56. mage_ai/orchestration/db/models/secrets.py +11 -1
  57. mage_ai/orchestration/job_manager.py +19 -0
  58. mage_ai/orchestration/metrics/pipeline_run.py +1 -1
  59. mage_ai/orchestration/notification/sender.py +2 -2
  60. mage_ai/orchestration/pipeline_scheduler_original.py +150 -6
  61. mage_ai/orchestration/pipeline_scheduler_project_platform.py +4 -5
  62. mage_ai/orchestration/queue/config.py +11 -1
  63. mage_ai/orchestration/queue/process_queue.py +4 -0
  64. mage_ai/orchestration/utils/distributed_lock.py +8 -1
  65. mage_ai/orchestration/utils/resources.py +56 -2
  66. mage_ai/sample_datasets/salary_survey.csv +52 -52
  67. mage_ai/server/api/base.py +41 -0
  68. mage_ai/server/api/constants.py +1 -0
  69. mage_ai/server/api/triggers.py +9 -0
  70. mage_ai/server/constants.py +1 -1
  71. mage_ai/server/frontend_dist/404.html +3 -3
  72. mage_ai/server/frontend_dist/_next/static/TUo4RceCdMufBTBTq8CAq/_buildManifest.js +1 -0
  73. mage_ai/server/frontend_dist/_next/static/chunks/{1187-839336d276186105.js → 1187-4560c3895e1d7099.js} +1 -1
  74. mage_ai/server/frontend_dist/_next/static/chunks/{1598-0adca9dce3ba4c60.js → 1598-cbf3f5a6078fc3f5.js} +1 -1
  75. mage_ai/server/frontend_dist/_next/static/chunks/2717-638a944d24d5abde.js +1 -0
  76. mage_ai/server/frontend_dist/_next/static/chunks/3548-36f746b1824004f2.js +1 -0
  77. mage_ai/server/frontend_dist/_next/static/chunks/{3763-39a5174f6a3924db.js → 3763-aabe2703076636b0.js} +1 -1
  78. mage_ai/server/frontend_dist/_next/static/chunks/3782-3e2acb5ed45b582b.js +1 -0
  79. mage_ai/server/frontend_dist/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
  80. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/5627-d5e559859dd0e1e0.js → frontend_dist/_next/static/chunks/5627-10e76bafa5a26f5f.js} +1 -1
  81. mage_ai/server/frontend_dist/_next/static/chunks/{5699-e49718dfc9eb2854.js → 5699-e99379e332bd0b41.js} +1 -1
  82. mage_ai/server/frontend_dist/_next/static/chunks/{7966-163da2621b8c987c.js → 7966-a5a7db345ce81263.js} +1 -1
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-b697b35dfc4e6e26.js +2 -0
  84. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/compute-ed67fa8e81662e8b.js → frontend_dist/_next/static/chunks/pages/compute-9e2dea78024e3bb4.js} +1 -1
  85. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/files-e0ecd7ced09a63b2.js → frontend_dist/_next/static/chunks/pages/files-e08c7fe76f968f9c.js} +1 -1
  86. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/{[...slug]-c7a729477ecda50e.js → [...slug]-30c3807057a4e65b.js} +1 -1
  87. mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-data-products-fd6ae6a358a60a0c.js → global-data-products-8dcb3b31af9e0e39.js} +1 -1
  88. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-8e50243797a7fe59.js → frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-85a64b64d27214b6.js} +1 -1
  89. mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-hooks-d0c003446332dc0d.js → global-hooks-4ff959d51b8a9502.js} +1 -1
  90. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{files-a69ed8e9f814490c.js → files-d08a460641d0efaa.js} +1 -1
  91. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{overview-1aad7093c6d39257.js → overview-aae747f487e08d51.js} +1 -1
  92. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{pipeline-runs-528d30e0d13b0cc7.js → pipeline-runs-09a842d64a6ada62.js} +1 -1
  93. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{settings-fb9201d9cf63031d.js → settings-2e98e57d9376a458.js} +1 -1
  94. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/{[user]-000f5a980a07da39.js → [user]-7be6e41ad66089bb.js} +1 -1
  95. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-e4e613f6e817a733.js → frontend_dist/_next/static/chunks/pages/manage/users/new-4c088833063bfa07.js} +1 -1
  96. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
  97. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/manage-34d718b8a4066c23.js → frontend_dist/_next/static/chunks/pages/manage-868fcd8cbeb265f0.js} +1 -1
  98. mage_ai/server/frontend_dist/_next/static/chunks/pages/{oauth-3bfd1b8d7f036726.js → oauth-6ceceb62191dfe8a.js} +1 -1
  99. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
  100. mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-5f8c100e648efa8a.js → pipeline-runs-2d0136b51b57de93.js} +1 -1
  101. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-688c652f3296bb9c.js → [...slug]-1ad5238742e25b4c.js} +1 -1
  102. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-bd11e87d026bfbf9.js +1 -0
  103. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{dashboard-1236e36d39b1637d.js → dashboard-0f4f47f721b0723f.js} +1 -1
  104. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-5ae8efe9e0530212.js +1 -0
  105. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-fe91dfb0091f6bc6.js +1 -0
  106. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-0d68d4bf6290fefb.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-cf794b2d22a80f31.js} +1 -1
  107. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-9254358d58f07714.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-a964caef91bed9e1.js} +1 -1
  108. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-821001e690caebe2.js → monitors-80bebb4401eefe25.js} +1 -1
  109. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-2eae7cb017027682.js +1 -0
  110. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-2d4b2a0800a66b33.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-776b2e5b0b6ceba8.js} +1 -1
  111. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-03d9bca3bc5e6088.js +1 -0
  112. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-707ed8ca942ca802.js +1 -0
  113. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/{[...slug]-259143ed3cf59e31.js → [...slug]-8429f17d4146e1ec.js} +1 -1
  114. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-193045d9836d8d80.js +1 -0
  115. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-d25d07db166cbb04.js +1 -0
  116. mage_ai/server/frontend_dist/_next/static/chunks/pages/platform/global-hooks/{[...slug]-5eeec927e4202b63.js → [...slug]-6834ae87bd668cb2.js} +1 -1
  117. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/platform/global-hooks-fbe9ad995d46d837.js → frontend_dist/_next/static/chunks/pages/platform/global-hooks-b3f7309a23e592b2.js} +1 -1
  118. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-fc659962d4015cb3.js → profile-f8b7374385e1f1bf.js} +1 -1
  119. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-8de68502a9afa299.js +1 -0
  120. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-a4f88c334414402b.js → frontend_dist/_next/static/chunks/pages/settings/platform/settings-50fb6a34f3913f1f.js} +1 -1
  121. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-4deb9579ef99a3c6.js → [...slug]-2e5c098c21ea32b7.js} +1 -1
  122. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-e0cda2f2bfce8d61.js → permissions-54e4b15b9585bfc4.js} +1 -1
  123. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-040f83d75d0f6537.js +1 -0
  124. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-910257d16c604ebd.js → [...slug]-95088f43034e3c95.js} +1 -1
  125. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{roles-4f7a0756806cee34.js → roles-e9149e1fcf218f42.js} +1 -1
  126. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{sync-data-208d6f955204d704.js → sync-data-75b67ae4a00818ef.js} +1 -1
  127. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-c89dc67e5a1706a8.js → [...slug]-557dda05ca6c6124.js} +1 -1
  128. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
  129. mage_ai/server/frontend_dist/_next/static/chunks/pages/{sign-in-054b33312d3193c3.js → sign-in-593c40985d63fcf7.js} +1 -1
  130. mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/{[...slug]-b6ed6a5d818bfd20.js → [...slug]-252c4b6b818345d5.js} +1 -1
  131. mage_ai/server/frontend_dist/_next/static/chunks/pages/{templates-852357bc983af2ea.js → templates-ca528bc607753ab8.js} +1 -1
  132. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/terminal-1f9c56d671bbc67d.js → frontend_dist/_next/static/chunks/pages/terminal-287362c1defcc96b.js} +1 -1
  133. mage_ai/server/frontend_dist/_next/static/chunks/pages/test-2f83af8c9f1378fe.js +1 -0
  134. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-d9de73fb799efed8.js +1 -0
  135. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/version-control-ae3469b992a341d6.js → frontend_dist/_next/static/chunks/pages/version-control-573f0225d7a703ed.js} +1 -1
  136. mage_ai/server/frontend_dist/block-layout.html +3 -3
  137. mage_ai/server/frontend_dist/compute.html +6 -6
  138. mage_ai/server/frontend_dist/files.html +6 -6
  139. mage_ai/server/frontend_dist/global-data-products/[...slug].html +6 -6
  140. mage_ai/server/frontend_dist/global-data-products.html +6 -6
  141. mage_ai/server/frontend_dist/global-hooks/[...slug].html +6 -6
  142. mage_ai/server/frontend_dist/global-hooks.html +6 -6
  143. mage_ai/server/frontend_dist/index.html +3 -3
  144. mage_ai/server/frontend_dist/manage/files.html +6 -6
  145. mage_ai/server/frontend_dist/manage/overview.html +6 -6
  146. mage_ai/server/frontend_dist/manage/pipeline-runs.html +6 -6
  147. mage_ai/server/frontend_dist/manage/settings.html +6 -6
  148. mage_ai/server/frontend_dist/manage/users/[user].html +6 -6
  149. mage_ai/server/frontend_dist/manage/users/new.html +6 -6
  150. mage_ai/server/frontend_dist/manage/users.html +6 -6
  151. mage_ai/server/frontend_dist/manage.html +6 -6
  152. mage_ai/server/frontend_dist/oauth.html +5 -5
  153. mage_ai/server/frontend_dist/overview.html +6 -6
  154. mage_ai/server/frontend_dist/pipeline-runs.html +6 -6
  155. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  156. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +6 -6
  157. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +6 -6
  158. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +3 -3
  159. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +6 -6
  160. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  161. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  162. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +6 -6
  163. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +6 -6
  164. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +6 -6
  165. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +6 -6
  166. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +6 -6
  167. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  168. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +6 -6
  169. mage_ai/server/frontend_dist/pipelines/[pipeline].html +3 -3
  170. mage_ai/server/frontend_dist/pipelines.html +6 -6
  171. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +6 -6
  172. mage_ai/server/frontend_dist/platform/global-hooks.html +6 -6
  173. mage_ai/server/frontend_dist/settings/account/profile.html +6 -6
  174. mage_ai/server/frontend_dist/settings/platform/preferences.html +6 -6
  175. mage_ai/server/frontend_dist/settings/platform/settings.html +6 -6
  176. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +6 -6
  177. mage_ai/server/frontend_dist/settings/workspace/permissions.html +6 -6
  178. mage_ai/server/frontend_dist/settings/workspace/preferences.html +6 -6
  179. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +6 -6
  180. mage_ai/server/frontend_dist/settings/workspace/roles.html +6 -6
  181. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +6 -6
  182. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +6 -6
  183. mage_ai/server/frontend_dist/settings/workspace/users.html +6 -6
  184. mage_ai/server/frontend_dist/settings.html +3 -3
  185. mage_ai/server/frontend_dist/sign-in.html +7 -7
  186. mage_ai/server/frontend_dist/templates/[...slug].html +6 -6
  187. mage_ai/server/frontend_dist/templates.html +6 -6
  188. mage_ai/server/frontend_dist/terminal.html +6 -6
  189. mage_ai/server/frontend_dist/test.html +3 -3
  190. mage_ai/server/frontend_dist/triggers.html +6 -6
  191. mage_ai/server/frontend_dist/v2/canvas.html +2 -2
  192. mage_ai/server/frontend_dist/v2.html +2 -2
  193. mage_ai/server/frontend_dist/version-control.html +6 -6
  194. mage_ai/server/frontend_dist_base_path_template/404.html +3 -3
  195. mage_ai/server/frontend_dist_base_path_template/_next/static/2QL-FT4lFR0a9bDZ7lNd9/_buildManifest.js +1 -0
  196. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1187-839336d276186105.js → 1187-4560c3895e1d7099.js} +1 -1
  197. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1598-0adca9dce3ba4c60.js → 1598-cbf3f5a6078fc3f5.js} +1 -1
  198. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-638a944d24d5abde.js +1 -0
  199. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-36f746b1824004f2.js +1 -0
  200. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3763-39a5174f6a3924db.js → 3763-aabe2703076636b0.js} +1 -1
  201. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-3e2acb5ed45b582b.js +1 -0
  202. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
  203. mage_ai/server/{frontend_dist/_next/static/chunks/5627-d5e559859dd0e1e0.js → frontend_dist_base_path_template/_next/static/chunks/5627-10e76bafa5a26f5f.js} +1 -1
  204. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{5699-e49718dfc9eb2854.js → 5699-e99379e332bd0b41.js} +1 -1
  205. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7966-163da2621b8c987c.js → 7966-a5a7db345ce81263.js} +1 -1
  206. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-f205accb03b9ff43.js +2 -0
  207. mage_ai/server/{frontend_dist/_next/static/chunks/pages/compute-ed67fa8e81662e8b.js → frontend_dist_base_path_template/_next/static/chunks/pages/compute-9e2dea78024e3bb4.js} +1 -1
  208. mage_ai/server/{frontend_dist/_next/static/chunks/pages/files-e0ecd7ced09a63b2.js → frontend_dist_base_path_template/_next/static/chunks/pages/files-e08c7fe76f968f9c.js} +1 -1
  209. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/{[...slug]-c7a729477ecda50e.js → [...slug]-30c3807057a4e65b.js} +1 -1
  210. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-data-products-fd6ae6a358a60a0c.js → global-data-products-8dcb3b31af9e0e39.js} +1 -1
  211. mage_ai/server/{frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-8e50243797a7fe59.js → frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-85a64b64d27214b6.js} +1 -1
  212. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-hooks-d0c003446332dc0d.js → global-hooks-4ff959d51b8a9502.js} +1 -1
  213. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{files-a69ed8e9f814490c.js → files-d08a460641d0efaa.js} +1 -1
  214. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{overview-1aad7093c6d39257.js → overview-aae747f487e08d51.js} +1 -1
  215. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{pipeline-runs-528d30e0d13b0cc7.js → pipeline-runs-09a842d64a6ada62.js} +1 -1
  216. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{settings-fb9201d9cf63031d.js → settings-2e98e57d9376a458.js} +1 -1
  217. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/{[user]-000f5a980a07da39.js → [user]-7be6e41ad66089bb.js} +1 -1
  218. mage_ai/server/{frontend_dist/_next/static/chunks/pages/manage/users/new-e4e613f6e817a733.js → frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-4c088833063bfa07.js} +1 -1
  219. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
  220. mage_ai/server/{frontend_dist/_next/static/chunks/pages/manage-34d718b8a4066c23.js → frontend_dist_base_path_template/_next/static/chunks/pages/manage-868fcd8cbeb265f0.js} +1 -1
  221. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{oauth-3bfd1b8d7f036726.js → oauth-6ceceb62191dfe8a.js} +1 -1
  222. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
  223. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-5f8c100e648efa8a.js → pipeline-runs-2d0136b51b57de93.js} +1 -1
  224. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-688c652f3296bb9c.js → [...slug]-1ad5238742e25b4c.js} +1 -1
  225. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-bd11e87d026bfbf9.js +1 -0
  226. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{dashboard-1236e36d39b1637d.js → dashboard-0f4f47f721b0723f.js} +1 -1
  227. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-5ae8efe9e0530212.js +1 -0
  228. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-fe91dfb0091f6bc6.js +1 -0
  229. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-0d68d4bf6290fefb.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-cf794b2d22a80f31.js} +1 -1
  230. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-9254358d58f07714.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-a964caef91bed9e1.js} +1 -1
  231. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-821001e690caebe2.js → monitors-80bebb4401eefe25.js} +1 -1
  232. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-2eae7cb017027682.js +1 -0
  233. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-2d4b2a0800a66b33.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-776b2e5b0b6ceba8.js} +1 -1
  234. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-03d9bca3bc5e6088.js +1 -0
  235. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-707ed8ca942ca802.js +1 -0
  236. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/{[...slug]-259143ed3cf59e31.js → [...slug]-8429f17d4146e1ec.js} +1 -1
  237. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-193045d9836d8d80.js +1 -0
  238. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-d25d07db166cbb04.js +1 -0
  239. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/platform/global-hooks/{[...slug]-5eeec927e4202b63.js → [...slug]-6834ae87bd668cb2.js} +1 -1
  240. mage_ai/server/{frontend_dist/_next/static/chunks/pages/platform/global-hooks-fbe9ad995d46d837.js → frontend_dist_base_path_template/_next/static/chunks/pages/platform/global-hooks-b3f7309a23e592b2.js} +1 -1
  241. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/{profile-fc659962d4015cb3.js → profile-f8b7374385e1f1bf.js} +1 -1
  242. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-8de68502a9afa299.js +1 -0
  243. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/settings-a4f88c334414402b.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-50fb6a34f3913f1f.js} +1 -1
  244. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-4deb9579ef99a3c6.js → [...slug]-2e5c098c21ea32b7.js} +1 -1
  245. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-e0cda2f2bfce8d61.js → permissions-54e4b15b9585bfc4.js} +1 -1
  246. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-040f83d75d0f6537.js +1 -0
  247. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-910257d16c604ebd.js → [...slug]-95088f43034e3c95.js} +1 -1
  248. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{roles-4f7a0756806cee34.js → roles-e9149e1fcf218f42.js} +1 -1
  249. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{sync-data-208d6f955204d704.js → sync-data-75b67ae4a00818ef.js} +1 -1
  250. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-c89dc67e5a1706a8.js → [...slug]-557dda05ca6c6124.js} +1 -1
  251. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
  252. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{sign-in-054b33312d3193c3.js → sign-in-593c40985d63fcf7.js} +1 -1
  253. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/{[...slug]-b6ed6a5d818bfd20.js → [...slug]-252c4b6b818345d5.js} +1 -1
  254. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{templates-852357bc983af2ea.js → templates-ca528bc607753ab8.js} +1 -1
  255. mage_ai/server/{frontend_dist/_next/static/chunks/pages/terminal-1f9c56d671bbc67d.js → frontend_dist_base_path_template/_next/static/chunks/pages/terminal-287362c1defcc96b.js} +1 -1
  256. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/test-2f83af8c9f1378fe.js +1 -0
  257. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-d9de73fb799efed8.js +1 -0
  258. mage_ai/server/{frontend_dist/_next/static/chunks/pages/version-control-ae3469b992a341d6.js → frontend_dist_base_path_template/_next/static/chunks/pages/version-control-573f0225d7a703ed.js} +1 -1
  259. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-12ad70eb5c31aa92.js → webpack-5f4be622608d9267.js} +1 -1
  260. mage_ai/server/frontend_dist_base_path_template/block-layout.html +3 -3
  261. mage_ai/server/frontend_dist_base_path_template/compute.html +6 -6
  262. mage_ai/server/frontend_dist_base_path_template/files.html +6 -6
  263. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +6 -6
  264. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +6 -6
  265. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +6 -6
  266. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +6 -6
  267. mage_ai/server/frontend_dist_base_path_template/index.html +3 -3
  268. mage_ai/server/frontend_dist_base_path_template/manage/files.html +6 -6
  269. mage_ai/server/frontend_dist_base_path_template/manage/overview.html +6 -6
  270. mage_ai/server/frontend_dist_base_path_template/manage/pipeline-runs.html +6 -6
  271. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +6 -6
  272. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +6 -6
  273. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +6 -6
  274. mage_ai/server/frontend_dist_base_path_template/manage/users.html +6 -6
  275. mage_ai/server/frontend_dist_base_path_template/manage.html +6 -6
  276. mage_ai/server/frontend_dist_base_path_template/oauth.html +5 -5
  277. mage_ai/server/frontend_dist_base_path_template/overview.html +6 -6
  278. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +6 -6
  279. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +6 -6
  280. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +6 -6
  281. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +6 -6
  282. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +3 -3
  283. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +6 -6
  284. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +6 -6
  285. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
  286. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +6 -6
  287. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +6 -6
  288. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +6 -6
  289. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +6 -6
  290. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +6 -6
  291. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +6 -6
  292. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +6 -6
  293. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +3 -3
  294. mage_ai/server/frontend_dist_base_path_template/pipelines.html +6 -6
  295. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +6 -6
  296. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +6 -6
  297. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +6 -6
  298. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +6 -6
  299. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +6 -6
  300. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +6 -6
  301. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +6 -6
  302. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +6 -6
  303. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +6 -6
  304. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +6 -6
  305. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +6 -6
  306. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +6 -6
  307. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +6 -6
  308. mage_ai/server/frontend_dist_base_path_template/settings.html +3 -3
  309. mage_ai/server/frontend_dist_base_path_template/sign-in.html +7 -7
  310. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +6 -6
  311. mage_ai/server/frontend_dist_base_path_template/templates.html +6 -6
  312. mage_ai/server/frontend_dist_base_path_template/terminal.html +6 -6
  313. mage_ai/server/frontend_dist_base_path_template/test.html +3 -3
  314. mage_ai/server/frontend_dist_base_path_template/triggers.html +6 -6
  315. mage_ai/server/frontend_dist_base_path_template/v2/canvas.html +2 -2
  316. mage_ai/server/frontend_dist_base_path_template/v2.html +2 -2
  317. mage_ai/server/frontend_dist_base_path_template/version-control.html +6 -6
  318. mage_ai/server/scheduler_manager.py +2 -0
  319. mage_ai/server/server.py +13 -0
  320. mage_ai/server/terminal_server.py +3 -0
  321. mage_ai/server/utils/output_display.py +5 -3
  322. mage_ai/services/aws/events/events.py +2 -2
  323. mage_ai/services/gcp/cloud_run/cloud_run.py +1 -1
  324. mage_ai/services/teams/config.py +13 -2
  325. mage_ai/services/teams/teams.py +13 -11
  326. mage_ai/settings/server.py +12 -1
  327. mage_ai/shared/constants.py +3 -1
  328. mage_ai/shared/croniter.py +1398 -0
  329. mage_ai/shared/enum.py +2 -5
  330. mage_ai/shared/environments.py +27 -3
  331. mage_ai/streaming/sinks/elasticsearch.py +15 -5
  332. mage_ai/streaming/sinks/kafka.py +21 -3
  333. mage_ai/streaming/sources/kafka.py +64 -7
  334. mage_ai/streaming/sources/kafka_oauth.py +182 -0
  335. mage_ai/tests/api/endpoints/test_blocks.py +1 -101
  336. mage_ai/tests/api/endpoints/test_configuration_options.py +1 -48
  337. mage_ai/tests/api/endpoints/test_configuration_options_project_platform.py +68 -0
  338. mage_ai/tests/api/endpoints/test_custom_designs.py +1 -106
  339. mage_ai/tests/api/endpoints/test_custom_designs_project_platform.py +132 -0
  340. mage_ai/tests/api/endpoints/test_dbt_blocks.py +111 -0
  341. mage_ai/tests/api/endpoints/test_file_contents.py +0 -48
  342. mage_ai/tests/api/endpoints/test_file_contents_with_project_platform.py +66 -0
  343. mage_ai/tests/api/endpoints/test_pipelines.py +0 -134
  344. mage_ai/tests/api/endpoints/test_pipelines_with_project_platform.py +143 -0
  345. mage_ai/tests/data_preparation/executors/test_block_executor.py +3 -3
  346. mage_ai/tests/data_preparation/logging/test_logger_manager.py +24 -5
  347. mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +1 -3
  348. mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +3 -3
  349. mage_ai/tests/data_preparation/models/test_block.py +7 -0
  350. mage_ai/tests/data_preparation/models/test_pipeline.py +55 -0
  351. mage_ai/tests/data_preparation/models/test_variable.py +2 -0
  352. mage_ai/tests/data_preparation/test_repo_manager.py +0 -63
  353. mage_ai/tests/data_preparation/test_repo_manager_project_platform.py +67 -0
  354. mage_ai/tests/data_preparation/test_variable_manager.py +0 -51
  355. mage_ai/tests/data_preparation/test_variable_manager_project_platform.py +41 -0
  356. mage_ai/tests/io/create_table/test_postgresql.py +28 -0
  357. mage_ai/tests/orchestration/db/models/test_schedules.py +1 -1
  358. mage_ai/tests/orchestration/notification/test_config.py +3 -3
  359. mage_ai/tests/orchestration/notification/test_sender.py +5 -1
  360. mage_ai/tests/orchestration/utils/__init__.py +0 -0
  361. mage_ai/tests/orchestration/utils/test_resources.py +235 -0
  362. mage_ai/tests/shared/test_croniter.py +2541 -0
  363. mage_ai/tests/streaming/sinks/test_kafka.py +130 -0
  364. mage_ai/tests/streaming/sources/test_kafka.py +125 -3
  365. mage_ai/tests/streaming/sources/test_kafka_oauth.py +208 -0
  366. mage_ai/tests/streaming/sources/test_kafka_raw_value.py +105 -0
  367. mage_ai/usage_statistics/logger.py +99 -15
  368. mage_ai-0.9.79.dist-info/METADATA +358 -0
  369. {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/RECORD +377 -359
  370. {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/WHEEL +1 -1
  371. mage_ai/server/frontend_dist/_next/static/chunks/1557-1ad0c64c2d08e569.js +0 -1
  372. mage_ai/server/frontend_dist/_next/static/chunks/2717-d65056b6b5e124eb.js +0 -1
  373. mage_ai/server/frontend_dist/_next/static/chunks/3548-b2c5edfb710886a6.js +0 -1
  374. mage_ai/server/frontend_dist/_next/static/chunks/3782-4b3091e550f809a2.js +0 -1
  375. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-5bdff745074fb350.js +0 -2
  376. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-a5e9d77ed5b50205.js +0 -1
  377. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-69af3253ad0d0d89.js +0 -1
  378. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-fe112809feb25b05.js +0 -1
  379. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e9ca358209cdf93d.js +0 -1
  380. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-a29f1615d2e7d330.js +0 -1
  381. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-6d382ae5bad9745c.js +0 -1
  382. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-cd49372ae1702963.js +0 -1
  383. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-135be8974f7f5f2b.js +0 -1
  384. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-3af13e89adff4d6c.js +0 -1
  385. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-b578b075a8d857e3.js +0 -1
  386. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-058d283ee178c038.js +0 -1
  387. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-7b02bb70462144cb.js +0 -1
  388. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-5212c01a9dc558da.js +0 -1
  389. mage_ai/server/frontend_dist/_next/static/chunks/pages/test-86b12cc12d4a625f.js +0 -1
  390. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-2481c40b18d5b6d4.js +0 -1
  391. mage_ai/server/frontend_dist/_next/static/pLWT6Sqd09xYpufCVIqnz/_buildManifest.js +0 -1
  392. mage_ai/server/frontend_dist_base_path_template/_next/static/JQewSAObpbhO0wrdAM6Ng/_buildManifest.js +0 -1
  393. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-1ad0c64c2d08e569.js +0 -1
  394. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d65056b6b5e124eb.js +0 -1
  395. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-b2c5edfb710886a6.js +0 -1
  396. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-4b3091e550f809a2.js +0 -1
  397. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-90de19bc03f1484b.js +0 -2
  398. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-a5e9d77ed5b50205.js +0 -1
  399. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-69af3253ad0d0d89.js +0 -1
  400. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-fe112809feb25b05.js +0 -1
  401. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e9ca358209cdf93d.js +0 -1
  402. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-a29f1615d2e7d330.js +0 -1
  403. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-6d382ae5bad9745c.js +0 -1
  404. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-cd49372ae1702963.js +0 -1
  405. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-135be8974f7f5f2b.js +0 -1
  406. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-3af13e89adff4d6c.js +0 -1
  407. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-b578b075a8d857e3.js +0 -1
  408. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-058d283ee178c038.js +0 -1
  409. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-7b02bb70462144cb.js +0 -1
  410. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-5212c01a9dc558da.js +0 -1
  411. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/test-86b12cc12d4a625f.js +0 -1
  412. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-2481c40b18d5b6d4.js +0 -1
  413. mage_ai-0.9.74.dist-info/METADATA +0 -544
  414. /mage_ai/server/frontend_dist/_next/static/{pLWT6Sqd09xYpufCVIqnz → TUo4RceCdMufBTBTq8CAq}/_ssgManifest.js +0 -0
  415. /mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-5bdff745074fb350.js.LICENSE.txt → _app-b697b35dfc4e6e26.js.LICENSE.txt} +0 -0
  416. /mage_ai/server/frontend_dist_base_path_template/_next/static/{JQewSAObpbhO0wrdAM6Ng → 2QL-FT4lFR0a9bDZ7lNd9}/_ssgManifest.js +0 -0
  417. /mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-90de19bc03f1484b.js.LICENSE.txt → _app-f205accb03b9ff43.js.LICENSE.txt} +0 -0
  418. {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/entry_points.txt +0 -0
  419. {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info/licenses}/LICENSE +0 -0
  420. {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,9 @@ from typing import Any, Dict, Optional, Tuple, Union
5
5
 
6
6
  import dbt.flags as flags
7
7
  import pandas as pd
8
- from dbt.adapters.base import BaseRelation, Credentials
8
+ from dbt.adapters.base.relation import BaseRelation
9
+ from dbt.adapters.contracts.connection import AdapterResponse, Credentials
10
+ from dbt.adapters.contracts.relation import RelationType
9
11
  from dbt.adapters.factory import (
10
12
  Adapter,
11
13
  cleanup_connections,
@@ -13,10 +15,10 @@ from dbt.adapters.factory import (
13
15
  register_adapter,
14
16
  reset_adapters,
15
17
  )
16
- from dbt.config.profile import read_user_config
18
+ from dbt.config.project import read_project_flags
17
19
  from dbt.config.runtime import RuntimeConfig
18
- from dbt.contracts.connection import AdapterResponse
19
- from dbt.contracts.relation import RelationType
20
+ from dbt.context.providers import generate_runtime_macro_context
21
+ from dbt.mp_context import get_mp_context
20
22
 
21
23
  from mage_ai.data_preparation.models.block.dbt.profiles import Profiles
22
24
  from mage_ai.shared.environments import is_debug
@@ -79,7 +81,11 @@ class DBTAdapter:
79
81
  # remove interpolated profiles.yml
80
82
  self.__profiles.clean()
81
83
 
82
- def execute(self, sql: str, fetch: bool = False) -> Tuple[AdapterResponse, pd.DataFrame]:
84
+ def execute(
85
+ self,
86
+ sql: str,
87
+ fetch: bool = False
88
+ ) -> Tuple[AdapterResponse, pd.DataFrame]:
83
89
  """
84
90
  Executes any sql statement using the dbt adapter.
85
91
 
@@ -135,6 +141,8 @@ class DBTAdapter:
135
141
  package
136
142
  )
137
143
 
144
+ self.__adapter.set_macro_resolver(manifest)
145
+
138
146
  # create a context for the macro (e.g. downstream macros)
139
147
  from dbt.context.providers import generate_runtime_macro_context
140
148
  macro_context = generate_runtime_macro_context(
@@ -203,7 +211,7 @@ class DBTAdapter:
203
211
  # set dbt flags
204
212
  # Need to add profiles.yml file
205
213
  try:
206
- user_config = read_user_config(profiles_path)
214
+ user_config = read_project_flags(self.project_path, profiles_path)
207
215
  except Exception as err:
208
216
  print(f'[ERROR] DBTAdapter.open: {err}.')
209
217
 
@@ -211,7 +219,10 @@ class DBTAdapter:
211
219
  not profiles_path.endswith('profiles.yml'):
212
220
 
213
221
  try:
214
- user_config = read_user_config(os.path.join(profiles_path, 'profiles.yml'))
222
+ user_config = read_project_flags(
223
+ self.project_path,
224
+ os.path.join(profiles_path, 'profiles.yml')
225
+ )
215
226
  except Exception as err2:
216
227
  print(f'[ERROR] DBTAdapter.open: {err2}.')
217
228
  raise err
@@ -227,9 +238,10 @@ class DBTAdapter:
227
238
  config = RuntimeConfig.from_args(adapter_config)
228
239
  reset_adapters()
229
240
  # register the correct adapter from config
230
- register_adapter(config)
241
+ register_adapter(config, mp_context=get_mp_context())
231
242
  # load the adapter
232
243
  self.__adapter = get_adapter(config)
244
+ self.__adapter.set_macro_context_generator(generate_runtime_macro_context)
233
245
  # connect
234
246
  self.__adapter.acquire_connection('mage_dbt_adapter_' + uuid.uuid4().hex)
235
247
  return self
@@ -1 +0,0 @@
1
- CHILD_DATA_VARIABLE_UUID = 'output_0'
@@ -1,14 +1,12 @@
1
1
  from typing import Any, Iterable, List, Optional, Sequence
2
2
 
3
3
  from mage_ai.data.tabular.reader import read_metadata
4
- from mage_ai.data_preparation.models.block.dynamic.constants import (
5
- CHILD_DATA_VARIABLE_UUID,
6
- )
7
4
  from mage_ai.data_preparation.models.block.dynamic.utils import (
8
5
  is_dynamic_block,
9
6
  is_dynamic_block_child,
10
7
  should_reduce_output,
11
8
  )
9
+ from mage_ai.data_preparation.models.constants import CHILD_DATA_VARIABLE_UUID
12
10
  from mage_ai.data_preparation.models.variables.cache import VariableAggregateCache
13
11
  from mage_ai.data_preparation.models.variables.constants import (
14
12
  VariableAggregateDataType,
@@ -343,7 +343,13 @@ def format_output_data(
343
343
  columns=columns_to_display,
344
344
  rows=[
345
345
  list(row.values())
346
- for row in json.loads(data[columns_to_display].write_json(row_oriented=True))
346
+ for row in json.loads(
347
+ simplejson.dumps(
348
+ data[columns_to_display].to_dicts(),
349
+ default=encode_complex,
350
+ ignore_nan=True,
351
+ )
352
+ )
347
353
  ],
348
354
  ),
349
355
  resource_usage=resource_usage,
@@ -8,7 +8,10 @@ import pandas as pd
8
8
  import simplejson
9
9
 
10
10
  from mage_ai.data_preparation.models.block import Block
11
- from mage_ai.data_preparation.models.constants import BlockType
11
+ from mage_ai.data_preparation.models.constants import (
12
+ CHILD_DATA_VARIABLE_UUID,
13
+ BlockType,
14
+ )
12
15
  from mage_ai.data_preparation.models.variables.constants import (
13
16
  DATAFRAME_CSV_FILE,
14
17
  VariableType,
@@ -81,7 +84,10 @@ def execute_r_code(
81
84
 
82
85
  if len(output_variable_objects) > 0:
83
86
  df = pd.read_csv(
84
- os.path.join(output_variable_objects[0].variable_path, DATAFRAME_CSV_FILE)
87
+ os.path.join(
88
+ output_variable_objects[0].variable_path,
89
+ DATAFRAME_CSV_FILE
90
+ )
85
91
  )
86
92
  else:
87
93
  df = None
@@ -129,14 +135,19 @@ def __render_r_script(
129
135
  raise Exception(
130
136
  f"Block execution for {block.type} with R language is not supported.",
131
137
  )
132
- template = template_env.get_template(BLOCK_TYPE_TO_EXECUTION_TEMPLATE[block.type])
138
+ template = template_env.get_template(
139
+ BLOCK_TYPE_TO_EXECUTION_TEMPLATE[block.type]
140
+ )
133
141
 
134
142
  output_variable_object = block.variable_object(
135
- "output_0",
143
+ CHILD_DATA_VARIABLE_UUID,
136
144
  execution_partition=execution_partition,
137
145
  )
138
146
  os.makedirs(output_variable_object.variable_path, exist_ok=True)
139
- output_path = os.path.join(output_variable_object.variable_path, DATAFRAME_CSV_FILE)
147
+ output_path = os.path.join(
148
+ output_variable_object.variable_path,
149
+ DATAFRAME_CSV_FILE
150
+ )
140
151
 
141
152
  global_vars_str = __render_global_vars(global_vars=global_vars)
142
153
 
@@ -150,6 +150,7 @@ def execute_sql_code(
150
150
  interpolate_vars_options = dict(
151
151
  block=block,
152
152
  dynamic_block_index=dynamic_block_index,
153
+ execution_partition=execution_partition,
153
154
  global_vars=global_vars,
154
155
  )
155
156
 
@@ -368,6 +369,7 @@ def execute_sql_code(
368
369
  loader,
369
370
  block,
370
371
  query_string,
372
+ disable_query_preprocessing=disable_query_preprocessing,
371
373
  configuration=configuration,
372
374
  should_query=should_query,
373
375
  )
@@ -67,9 +67,17 @@ def execute_raw_sql(
67
67
  query_string: str,
68
68
  configuration: Dict = None,
69
69
  should_query: bool = False,
70
+ disable_query_preprocessing: bool = False,
70
71
  ) -> List[Any]:
71
72
  if configuration is None:
72
73
  configuration = {}
74
+
75
+ if disable_query_preprocessing:
76
+ return loader.execute_query_raw(
77
+ query_string,
78
+ configuration=configuration,
79
+ )
80
+
73
81
  queries = []
74
82
  fetch_query_at_indexes = []
75
83
 
@@ -232,7 +232,8 @@ def interpolate_vars(
232
232
  content: str,
233
233
  global_vars: Dict = None,
234
234
  block=None,
235
- dynamic_block_index: int = None
235
+ dynamic_block_index: int = None,
236
+ execution_partition: str = None,
236
237
  ) -> str :
237
238
  if not content:
238
239
  return content
@@ -241,7 +242,10 @@ def interpolate_vars(
241
242
 
242
243
  if block:
243
244
  content = block.interpolate_content(
244
- content, variables=global_vars, dynamic_block_index=dynamic_block_index,
245
+ content,
246
+ variables=global_vars,
247
+ dynamic_block_index=dynamic_block_index,
248
+ execution_partition=execution_partition,
245
249
  )
246
250
 
247
251
  return Template(
@@ -15,7 +15,7 @@ DATA_INTEGRATION_CATALOG_FILE = 'data_integration_catalog.json'
15
15
  DATAFRAME_ANALYSIS_MAX_COLUMNS = 100
16
16
  DATAFRAME_ANALYSIS_MAX_ROWS = 100_000
17
17
  DATAFRAME_SAMPLE_COUNT = 1000
18
- DATAFRAME_SAMPLE_COUNT_PREVIEW = 10
18
+ DATAFRAME_SAMPLE_COUNT_PREVIEW = int(os.getenv('DATAFRAME_SAMPLE_COUNT_PREVIEW', 10) or 10)
19
19
  DATAFRAME_SAMPLE_MAX_COLUMNS = 1000
20
20
  DYNAMIC_CHILD_BLOCK_SAMPLE_COUNT_PREVIEW = 10
21
21
  LOGS_SUBDIR = '.logs'
@@ -27,6 +27,7 @@ PIPELINES_FOLDER = 'pipelines'
27
27
  PREFERENCES_FILE = '.preferences.yaml'
28
28
  REPO_CONFIG_FILE = 'metadata.yaml'
29
29
  VARIABLE_DIR = '.variables'
30
+ CHILD_DATA_VARIABLE_UUID = 'output_0'
30
31
 
31
32
  PIPELINE_RUN_STATUS_LAST_RUN_FAILED = 'last_run_failed'
32
33
 
@@ -81,6 +82,7 @@ class BlockColor(StrEnum):
81
82
 
82
83
 
83
84
  class CallbackStatus(StrEnum):
85
+ CANCELLED = 'cancelled'
84
86
  FAILURE = 'failure'
85
87
  SUCCESS = 'success'
86
88
 
@@ -125,6 +127,7 @@ BLOCK_LANGUAGE_TO_FILE_EXTENSION = {
125
127
 
126
128
 
127
129
  CALLBACK_STATUSES = [
130
+ CallbackStatus.CANCELLED,
128
131
  CallbackStatus.FAILURE,
129
132
  CallbackStatus.SUCCESS,
130
133
  ]
@@ -4,6 +4,7 @@ import json
4
4
  import os
5
5
  import shutil
6
6
  import tempfile
7
+ import time
7
8
  import zipfile
8
9
  from datetime import datetime, timezone
9
10
  from io import BytesIO
@@ -77,6 +78,7 @@ from mage_ai.orchestration.notification.sender import NotificationSender
77
78
  from mage_ai.settings.platform import build_repo_path_for_all_projects
78
79
  from mage_ai.settings.platform.constants import project_platform_activated
79
80
  from mage_ai.settings.repo import get_repo_path
81
+ from mage_ai.settings.server import RUN_PIPELINE_IN_ONE_PROCESS
80
82
  from mage_ai.shared.array import find
81
83
  from mage_ai.shared.hash import extract, ignore_keys, index_by, merge_dict
82
84
  from mage_ai.shared.io import safe_write, safe_write_async
@@ -127,7 +129,7 @@ class Pipeline:
127
129
 
128
130
  self.repo_path = repo_path or get_repo_path()
129
131
  self.retry_config = {}
130
- self.run_pipeline_in_one_process = False
132
+ self.run_pipeline_in_one_process = RUN_PIPELINE_IN_ONE_PROCESS
131
133
  self.schedules = []
132
134
  self.settings = {}
133
135
  self.tags = tags or []
@@ -884,7 +886,10 @@ class Pipeline:
884
886
  self.executor_type = config.get('executor_type')
885
887
  self.notification_config = config.get('notification_config') or {}
886
888
  self.retry_config = config.get('retry_config') or {}
887
- self.run_pipeline_in_one_process = config.get('run_pipeline_in_one_process', False)
889
+ self.run_pipeline_in_one_process = config.get(
890
+ 'run_pipeline_in_one_process',
891
+ RUN_PIPELINE_IN_ONE_PROCESS,
892
+ )
888
893
  self.settings = PipelineSettings.load(**config.get('settings') or {})
889
894
  self.spark_config = config.get('spark_config') or {}
890
895
  self.tags = config.get('tags') or []
@@ -2328,6 +2333,10 @@ class Pipeline:
2328
2333
  extension_uuid: str = None,
2329
2334
  widget: bool = False,
2330
2335
  ):
2336
+ # Introduce a small delay to prevent multiple changes from generating
2337
+ # identical timestamps for the pipeline YAML file
2338
+ time.sleep(0.0005)
2339
+
2331
2340
  blocks_current = sorted([b.uuid for b in self.blocks_by_uuid.values()])
2332
2341
 
2333
2342
  if block_uuid is not None:
@@ -214,10 +214,12 @@ class Project:
214
214
  return [self.repo_path]
215
215
 
216
216
  def projects(self) -> Dict:
217
- return project_platform_settings(
217
+ projects = project_platform_settings(
218
218
  context_data=self.context_data,
219
219
  mage_projects_only=True
220
220
  )
221
+ sorted_projects = {k: projects[k] for k in sorted(projects)}
222
+ return sorted_projects
221
223
 
222
224
  def is_feature_enabled(self, feature_name: FeatureUUID) -> bool:
223
225
  feature_enabled = self.features.get(feature_name.value, False)
@@ -5,12 +5,12 @@ from datetime import datetime, timezone
5
5
  from typing import Dict, List, Optional
6
6
 
7
7
  import yaml
8
- from croniter import croniter
9
8
 
10
9
  from mage_ai.data_preparation.models.constants import PIPELINES_FOLDER
11
10
  from mage_ai.settings.repo import get_repo_path
12
11
  from mage_ai.shared.config import BaseConfig
13
12
  from mage_ai.shared.constants import VALID_ENVS
13
+ from mage_ai.shared.croniter import croniter
14
14
  from mage_ai.shared.enum import StrEnum
15
15
  from mage_ai.shared.hash import index_by
16
16
  from mage_ai.shared.io import safe_write
@@ -121,7 +121,10 @@ class LocalStorage(BaseStorage):
121
121
  return pd.read_parquet(file_path, engine='pyarrow')
122
122
 
123
123
  def read_polars_parquet(self, file_path: str, **kwargs) -> pl.DataFrame:
124
- return pl.read_parquet(file_path, use_pyarrow=True)
124
+ try:
125
+ return pl.read_parquet(file_path, use_pyarrow=True)
126
+ except Exception:
127
+ return pl.read_parquet(file_path)
125
128
 
126
129
  def write_csv(self, df: pd.DataFrame, file_path: str) -> None:
127
130
  File.create_parent_directories(file_path)
@@ -19,6 +19,13 @@ GROUP_ROW_ACTIONS = 'Row actions'
19
19
  GROUP_SHIFT = 'Shift'
20
20
 
21
21
  TEMPLATES = [
22
+ dict(
23
+ block_type=BlockType.DATA_LOADER,
24
+ description='Load a Table from Airtable App.',
25
+ language=BlockLanguage.PYTHON,
26
+ name='Airtable',
27
+ path='data_loaders/airtable.py',
28
+ ),
22
29
  dict(
23
30
  block_type=BlockType.DATA_LOADER,
24
31
  description='Load a Delta Table from Amazon S3.',
@@ -2,6 +2,9 @@ connector_type: elasticsearch
2
2
  host: http://localhost
3
3
  index_name: elastic_index
4
4
  api_key: api_key_for_elastic_search
5
+ # # When using Data streams this must be set to create as they are Append-only indexes
6
+ # _op_type: None / index, create or update
7
+ # _source: None (Default '_doc') / Specify the source field
5
8
  # # Whether to verify SSL certificates to authenticate.
6
9
  # verify_certs: true
7
10
  # ca_cert: "certificate.cert"
@@ -0,0 +1,28 @@
1
+ {% extends "data_loaders/default.jinja" %}
2
+ {% block imports %}
3
+ from mage_ai.settings.repo import get_repo_path
4
+ from mage_ai.io.config import ConfigFileLoader
5
+ from mage_ai.io.airtable import Airtable
6
+ from os import path
7
+ {{ super() -}}
8
+ {% endblock %}
9
+
10
+
11
+ {% block content %}
12
+ @data_loader
13
+ def load_data_from_airtable(*args, **kwargs):
14
+ """
15
+ Template for loading data from Airtable.
16
+ Specify your configuration settings in 'io_config.yaml'.
17
+ """
18
+ config_path = path.join(get_repo_path(), 'io_config.yaml')
19
+ config_profile = 'default'
20
+
21
+ base_id = 'your_base_id'
22
+ table_name = 'your_table_name'
23
+
24
+ return Airtable.with_config(ConfigFileLoader(config_path, config_profile)).load(
25
+ base_id=base_id,
26
+ table_name=table_name
27
+ )
28
+ {% endblock %}
@@ -17,9 +17,12 @@ timeout: 5
17
17
 
18
18
  # Optional: TLS configuration
19
19
  use_tls: false
20
- # cafile: "path/to/ca.pem"
21
- # certfile: "path/to/client-cert.pem"
22
- # keyfile: "path/to/client-key.pem"
20
+
21
+ # Optional: SSL configuration
22
+ # ssl_config:
23
+ # cafile: "path/to/ca.pem"
24
+ # certfile: "path/to/client-cert.pem"
25
+ # keyfile: "path/to/client-key.pem"
23
26
 
24
27
  # Optional: NKEY seed string
25
28
  # nkeys_seed_str: "SUAPAEYJQOQHJ4"
@@ -11,6 +11,8 @@ default:
11
11
  ALGOLIA_APP_ID: app_id
12
12
  ALGOLIA_API_KEY: api_key
13
13
  ALGOLIA_INDEX_NAME: index_name
14
+ # Airtable
15
+ AIRTABLE_ACCESS_TOKEN: token
14
16
  # Azure
15
17
  AZURE_CLIENT_ID: "{{ env_var('AZURE_CLIENT_ID') }}"
16
18
  AZURE_CLIENT_SECRET: "{{ env_var('AZURE_CLIENT_SECRET') }}"
mage_ai/io/airtable.py ADDED
@@ -0,0 +1,104 @@
1
+ from typing import Union
2
+
3
+ import pandas as pd
4
+ import polars as pl
5
+ from pyairtable.api import Api
6
+
7
+ from mage_ai.io.base import BaseIO
8
+ from mage_ai.io.config import BaseConfigLoader, ConfigKey
9
+
10
+
11
+ class Airtable(BaseIO):
12
+ """
13
+ Handles data transfer between Airtable tables and the Mage app.
14
+ """
15
+
16
+ def __init__(
17
+ self,
18
+ token: str,
19
+ verbose: bool = True,
20
+ **kwargs) -> None:
21
+ """
22
+ Initializes a connection to Airtable.
23
+
24
+ Args:
25
+ token (str): Airtable API token.
26
+ verbose (bool, optional): Whether to print verbose output. Defaults to True.
27
+ **kwargs: Additional keyword arguments to pass to the pyairtable Api constructor.
28
+ """
29
+ super().__init__(verbose=verbose)
30
+ self.client = Api(token, **kwargs) # Create the Airtable API client
31
+
32
+ @classmethod
33
+ def with_config(
34
+ cls,
35
+ config: BaseConfigLoader
36
+ ) -> 'Airtable':
37
+ """
38
+ Initializes an Airtable client from a configuration loader.
39
+
40
+ Args:
41
+ config (BaseConfigLoader): Configuration loader object.
42
+
43
+ Raises:
44
+ ValueError: If no valid Airtable API token is found in the configuration.
45
+
46
+ Returns:
47
+ Airtable: An instance of the Airtable class.
48
+ """
49
+ if ConfigKey.AIRTABLE_ACCESS_TOKEN not in config:
50
+ raise ValueError(
51
+ 'No valid API token found for Airtable.'
52
+ 'You must specify your access token in your config.'
53
+ )
54
+
55
+ return cls(
56
+ token=config[ConfigKey.AIRTABLE_ACCESS_TOKEN]
57
+ )
58
+
59
+ def load(
60
+ self,
61
+ base_id: str,
62
+ table_name: str,
63
+ **kwargs,
64
+ ) -> pd.DataFrame:
65
+ """
66
+ Loads data from an Airtable table into a Pandas DataFrame.
67
+
68
+ Args:
69
+ base_id (str): The ID of the Airtable base (e.g., 'app*****').
70
+ table_name (str): The name or ID of the Airtable table (e.g., 'tbl*****').
71
+ **kwargs: Additional keyword arguments to pass to the pyairtable table.all() method.
72
+
73
+ Returns:
74
+ DataFrame: A Pandas DataFrame containing the data from the Airtable table.
75
+ """
76
+ with self.printer.print_msg(
77
+ f'Loading data frame from table \'{table_name}\' at airtable app \'{base_id}\''
78
+ ):
79
+ table = self.client.table(base_id, table_name) # Get the Airtable table
80
+ data = table.all(**kwargs) # Fetch all records from the table
81
+
82
+ # Flatten the Airtable data structure into a list of dictionaries
83
+ flattened_data = []
84
+ for record in data:
85
+ flattened_record = {
86
+ 'id': record['id'],
87
+ 'createdTime': record['createdTime']
88
+ }
89
+ fields = record['fields']
90
+ flattened_record.update(fields)
91
+ flattened_data.append(flattened_record)
92
+
93
+ return pd.DataFrame(flattened_data) # Create and return a DataFrame
94
+
95
+ def export(
96
+ self,
97
+ df: Union[pd.DataFrame, pl.DataFrame],
98
+ *args,
99
+ **kwargs
100
+ ) -> None:
101
+ """
102
+ Not implemented yet. This method is intended to export data to Airtable.
103
+ """
104
+ pass
mage_ai/io/base.py CHANGED
@@ -16,6 +16,7 @@ QUERY_ROW_LIMIT = 10_000_000
16
16
 
17
17
 
18
18
  class DataSource(StrEnum):
19
+ AIRTABLE = 'airtable'
19
20
  ALGOLIA = 'algolia'
20
21
  API = 'api'
21
22
  BIGQUERY = 'bigquery'
@@ -47,6 +48,26 @@ class FileFormat(StrEnum):
47
48
  PARQUET = 'parquet'
48
49
  HDF5 = 'hdf5'
49
50
  XML = 'xml'
51
+ EXCEL = 'excel'
52
+
53
+ @classmethod
54
+ def from_extension(cls, ext: str):
55
+ if ext == 'csv':
56
+ return cls.CSV
57
+ elif ext == 'json':
58
+ return cls.JSON
59
+ elif ext == 'parquet':
60
+ return cls.PARQUET
61
+ elif ext == 'hdf5':
62
+ return cls.HDF5
63
+ elif ext == 'xml':
64
+ return cls.XML
65
+ elif ext in ('xls', 'xlsx'):
66
+ return cls.EXCEL
67
+ else:
68
+ raise ValueError(
69
+ f'None file format found for this file extension: {ext}'
70
+ )
50
71
 
51
72
 
52
73
  class ExportWritePolicy(BaseEnum):
@@ -126,7 +147,9 @@ class BaseFile(BaseIO):
126
147
  pass
127
148
 
128
149
  def _get_file_format(self, filepath: Union[os.PathLike, str]) -> str:
129
- return os.path.splitext(os.path.basename(filepath))[-1][1:]
150
+ return FileFormat.from_extension(
151
+ os.path.splitext(os.path.basename(filepath))[-1][1:]
152
+ )
130
153
 
131
154
  def __get_reader(self, format: Union[FileFormat, str, None]) -> Callable:
132
155
  """
@@ -151,6 +174,8 @@ class BaseFile(BaseIO):
151
174
  return pd.read_hdf
152
175
  elif format == FileFormat.XML:
153
176
  return pd.read_xml
177
+ elif format == FileFormat.EXCEL:
178
+ return pd.read_excel
154
179
  else:
155
180
  raise ValueError(f"Invalid format '{format}' specified.")
156
181
 
@@ -249,6 +274,8 @@ class BaseFile(BaseIO):
249
274
  return df.write_hdf5
250
275
  elif format == FileFormat.XML:
251
276
  return df.write_xml
277
+ elif format == FileFormat.EXCEL:
278
+ return df.write_excel
252
279
  return df.write_parquet
253
280
 
254
281
  elif isinstance(df, DataFrame): # pandas DataFrame
@@ -260,6 +287,8 @@ class BaseFile(BaseIO):
260
287
  return df.to_hdf
261
288
  elif format == FileFormat.XML:
262
289
  return df.to_xml
290
+ elif format == FileFormat.EXCEL:
291
+ return df.to_excel
263
292
  return df.to_parquet
264
293
 
265
294
  def __del__(self):
mage_ai/io/bigquery.py CHANGED
@@ -1,7 +1,9 @@
1
+ import traceback
1
2
  import uuid
2
3
  from typing import Dict, List, Mapping, Union
3
4
 
4
5
  import numpy as np
6
+ import pandas as pd
5
7
  from google.cloud.bigquery import (
6
8
  Client,
7
9
  LoadJobConfig,
@@ -399,7 +401,41 @@ WHERE table_id = '{table_name}'
399
401
  # Clean column names
400
402
  if type(df) is DataFrame:
401
403
  df.columns = df.columns.str.replace(' ', '_')
404
+ table = None
405
+ try:
406
+ # Cast column types
407
+ table = self.client.get_table(table_id)
408
+ except Exception:
409
+ print(f'Table {table_id} does not exist.')
410
+ pass
402
411
 
412
+ if table is not None:
413
+ try:
414
+ timestamp_columns = [field.name for field in table.schema
415
+ if field.field_type == 'TIMESTAMP']
416
+
417
+ # Convert TIMESTAMP columns in DataFrame
418
+ for col in timestamp_columns:
419
+ if col in df.columns:
420
+ df[col] = pd.to_datetime(df[col])
421
+ except Exception:
422
+ print('Fail to cast column types in dataframe.')
423
+ traceback.print_exc()
424
+ if (
425
+ not config.schema and
426
+ config.write_disposition == WriteDisposition.WRITE_TRUNCATE
427
+ ):
428
+ df_columns = df.columns.tolist()
429
+ config.schema = [
430
+ SchemaField(
431
+ field.name,
432
+ field.field_type,
433
+ mode=field.mode,
434
+ fields=field.fields,
435
+ )
436
+ for field in table.schema
437
+ if field.name in df_columns
438
+ ]
403
439
  return self.client.load_table_from_dataframe(df, table_id, job_config=config).result()
404
440
 
405
441
  def execute(self, query_string: str, **kwargs) -> None: