mage-ai 0.9.67__py3-none-any.whl → 0.9.69__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 (307) hide show
  1. mage_ai/api/monitors/BaseMonitor.py +1 -2
  2. mage_ai/api/policies/PipelinePolicy.py +2 -0
  3. mage_ai/api/resources/BlockLayoutItemResource.py +2 -2
  4. mage_ai/api/resources/BlockResource.py +4 -3
  5. mage_ai/api/resources/CacheItemResource.py +1 -1
  6. mage_ai/api/resources/GitBranchResource.py +3 -5
  7. mage_ai/api/resources/PageBlockLayoutResource.py +2 -2
  8. mage_ai/api/resources/PipelineResource.py +13 -0
  9. mage_ai/api/resources/PipelineRunResource.py +10 -1
  10. mage_ai/api/resources/SeedResource.py +2 -1
  11. mage_ai/api/resources/SessionResource.py +13 -1
  12. mage_ai/authentication/permissions/constants.py +2 -0
  13. mage_ai/authentication/permissions/seed.py +32 -21
  14. mage_ai/authentication/providers/active_directory.py +4 -3
  15. mage_ai/authentication/providers/okta.py +22 -83
  16. mage_ai/cache/tag.py +3 -0
  17. mage_ai/cluster_manager/manage.py +4 -1
  18. mage_ai/data_preparation/executors/k8s_block_executor.py +8 -1
  19. mage_ai/data_preparation/executors/k8s_pipeline_executor.py +12 -1
  20. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +77 -7
  21. mage_ai/data_preparation/logging/gcs_logger_manager.py +7 -4
  22. mage_ai/data_preparation/models/block/__init__.py +28 -71
  23. mage_ai/data_preparation/models/block/block_factory.py +77 -0
  24. mage_ai/data_preparation/models/block/data_integration/mixins.py +16 -5
  25. mage_ai/data_preparation/models/block/dbt/block.py +5 -7
  26. mage_ai/data_preparation/models/block/dynamic/child.py +3 -0
  27. mage_ai/data_preparation/models/block/dynamic/variables.py +2 -2
  28. mage_ai/data_preparation/models/block/extension/utils.py +1 -0
  29. mage_ai/data_preparation/models/block/global_data_product/__init__.py +9 -3
  30. mage_ai/data_preparation/models/block/integration/__init__.py +13 -9
  31. mage_ai/data_preparation/models/block/platform/mixins.py +1 -1
  32. mage_ai/data_preparation/models/block/sql/__init__.py +1 -1
  33. mage_ai/data_preparation/models/pipeline.py +102 -19
  34. mage_ai/data_preparation/models/utils.py +6 -0
  35. mage_ai/data_preparation/models/variable.py +18 -4
  36. mage_ai/data_preparation/repo_manager.py +3 -2
  37. mage_ai/data_preparation/shared/utils.py +1 -1
  38. mage_ai/data_preparation/storage/gcs_storage.py +1 -1
  39. mage_ai/data_preparation/templates/constants.py +7 -0
  40. mage_ai/data_preparation/templates/data_exporters/mysql.py +2 -2
  41. mage_ai/data_preparation/templates/data_exporters/oracledb.py +27 -0
  42. mage_ai/data_preparation/templates/repo/metadata.yaml +1 -0
  43. mage_ai/io/bigquery.py +131 -58
  44. mage_ai/io/export_utils.py +3 -0
  45. mage_ai/io/mysql.py +38 -6
  46. mage_ai/io/oracledb.py +138 -3
  47. mage_ai/io/snowflake.py +152 -29
  48. mage_ai/io/sql.py +4 -0
  49. mage_ai/orchestration/db/__init__.py +2 -2
  50. mage_ai/orchestration/db/models/oauth.py +4 -4
  51. mage_ai/orchestration/db/models/schedules.py +10 -3
  52. mage_ai/orchestration/job_manager.py +6 -0
  53. mage_ai/orchestration/notification/sender.py +8 -0
  54. mage_ai/orchestration/pipeline_scheduler_original.py +26 -7
  55. mage_ai/orchestration/queue/celery_queue.py +8 -1
  56. mage_ai/orchestration/queue/process_queue.py +67 -4
  57. mage_ai/orchestration/queue/queue.py +8 -0
  58. mage_ai/server/constants.py +1 -1
  59. mage_ai/server/frontend_dist/404.html +2 -2
  60. mage_ai/server/{frontend_dist_base_path_template/_next/static/khKiaJtwrslgMmp4YSa1f → frontend_dist/_next/static/_krrrgup_C-dPOpX36S8I}/_buildManifest.js +1 -1
  61. mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
  64. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4241-ccd0126f5750cc35.js → frontend_dist/_next/static/chunks/4241-4499461184ba0d23.js} +1 -1
  65. mage_ai/server/frontend_dist/_next/static/chunks/5627-237a3de578538022.js +1 -0
  66. mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
  67. mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
  68. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7966-5c1786fb7e7a48f5.js → frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js} +1 -1
  69. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
  71. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
  72. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
  73. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
  74. mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
  75. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
  76. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
  77. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
  78. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
  79. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
  80. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js +1 -0
  81. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
  82. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
  84. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
  85. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js → frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js} +1 -1
  86. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
  87. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js → frontend_dist/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js} +1 -1
  88. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
  89. mage_ai/server/frontend_dist/block-layout.html +2 -2
  90. mage_ai/server/frontend_dist/compute.html +2 -2
  91. mage_ai/server/frontend_dist/files.html +2 -2
  92. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  93. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  94. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  95. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  96. mage_ai/server/frontend_dist/index.html +2 -2
  97. mage_ai/server/frontend_dist/manage/files.html +2 -2
  98. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  99. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  100. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  101. mage_ai/server/frontend_dist/manage/users.html +2 -2
  102. mage_ai/server/frontend_dist/manage.html +2 -2
  103. mage_ai/server/frontend_dist/oauth.html +3 -3
  104. mage_ai/server/frontend_dist/overview.html +2 -2
  105. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  106. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  107. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  108. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  109. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  110. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  111. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  112. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  113. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  114. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  115. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  116. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  117. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  118. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  119. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  120. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  121. mage_ai/server/frontend_dist/pipelines.html +2 -2
  122. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  123. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  124. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  125. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  126. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  127. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  128. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  129. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  130. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  131. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  132. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  133. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  134. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  135. mage_ai/server/frontend_dist/settings.html +2 -2
  136. mage_ai/server/frontend_dist/sign-in.html +5 -5
  137. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  138. mage_ai/server/frontend_dist/templates.html +2 -2
  139. mage_ai/server/frontend_dist/terminal.html +2 -2
  140. mage_ai/server/frontend_dist/test.html +2 -2
  141. mage_ai/server/frontend_dist/triggers.html +2 -2
  142. mage_ai/server/frontend_dist/version-control.html +2 -2
  143. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  144. mage_ai/server/{frontend_dist/_next/static/vPsMu6Fi2zrHaf2fRXKRO → frontend_dist_base_path_template/_next/static/KLL5mirre9d7_ZeEpaw3s}/_buildManifest.js +1 -1
  145. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
  146. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
  147. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
  148. mage_ai/server/{frontend_dist/_next/static/chunks/4241-ccd0126f5750cc35.js → frontend_dist_base_path_template/_next/static/chunks/4241-4499461184ba0d23.js} +1 -1
  149. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5627-237a3de578538022.js +1 -0
  150. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
  151. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
  152. mage_ai/server/{frontend_dist/_next/static/chunks/7966-5c1786fb7e7a48f5.js → frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js} +1 -1
  153. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
  154. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
  155. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
  156. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
  157. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
  158. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
  159. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
  160. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
  161. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
  162. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
  163. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
  164. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js +1 -0
  165. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
  166. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
  167. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
  168. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
  169. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js} +1 -1
  170. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
  171. mage_ai/server/{frontend_dist/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js → frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js} +1 -1
  172. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
  173. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  181. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  183. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
  188. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  191. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  192. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  193. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  194. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  195. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  196. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  197. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  198. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  199. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  200. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  201. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  202. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  203. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  204. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  205. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  206. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  207. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  208. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  209. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  210. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  211. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  212. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  213. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  214. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  215. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  216. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  217. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  218. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  219. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  220. mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
  221. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  222. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  223. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  224. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  225. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  226. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  227. mage_ai/server/scheduler_manager.py +7 -0
  228. mage_ai/server/server.py +12 -5
  229. mage_ai/server/websocket_server.py +1 -0
  230. mage_ai/services/k8s/job_manager.py +8 -0
  231. mage_ai/services/slack/slack.py +10 -1
  232. mage_ai/services/spark/spark.py +9 -2
  233. mage_ai/settings/backends.py +8 -8
  234. mage_ai/settings/keys/auth.py +2 -0
  235. mage_ai/settings/models/configuration_option.py +10 -9
  236. mage_ai/settings/server.py +1 -1
  237. mage_ai/shared/files.py +19 -1
  238. mage_ai/shared/path_fixer.py +3 -0
  239. mage_ai/streaming/sources/base.py +5 -0
  240. mage_ai/streaming/sources/influxdb.py +2 -0
  241. mage_ai/streaming/sources/kafka.py +2 -1
  242. mage_ai/streaming/sources/mongodb.py +4 -0
  243. mage_ai/tests/api/endpoints/mixins.py +10 -9
  244. mage_ai/tests/api/endpoints/test_seeds.py +24 -0
  245. mage_ai/tests/api/operations/test_sessions.py +53 -2
  246. mage_ai/tests/authentication/providers/test_okta.py +43 -0
  247. mage_ai/tests/data_preparation/models/block/dbt/test_block.py +2 -2
  248. mage_ai/tests/data_preparation/models/block/dbt/test_block_sql.py +1 -1
  249. mage_ai/tests/data_preparation/models/block/dbt/test_block_yaml.py +1 -1
  250. mage_ai/tests/data_preparation/models/test_block.py +2 -1
  251. mage_ai/tests/orchestration/db/models/test_oauth.py +3 -3
  252. mage_ai/tests/orchestration/queue/test_process_queue.py +1 -0
  253. mage_ai/tests/orchestration/test_pipeline_scheduler.py +2 -0
  254. mage_ai/tests/server/test_server.py +8 -4
  255. mage_ai/tests/settings/models/test_configuration_option.py +2 -2
  256. {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/METADATA +6 -6
  257. {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/RECORD +263 -259
  258. mage_ai/server/frontend_dist/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
  259. mage_ai/server/frontend_dist/_next/static/chunks/181-e61915415a976861.js +0 -1
  260. mage_ai/server/frontend_dist/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
  261. mage_ai/server/frontend_dist/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
  262. mage_ai/server/frontend_dist/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
  263. mage_ai/server/frontend_dist/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
  264. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +0 -1
  265. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +0 -1
  266. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
  267. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
  268. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
  269. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
  270. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-36377e679da2cd91.js +0 -1
  271. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
  272. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
  273. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
  274. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
  275. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
  276. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
  277. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
  278. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
  279. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
  280. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
  281. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/181-e61915415a976861.js +0 -1
  282. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
  283. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
  284. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
  285. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
  286. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +0 -1
  287. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +0 -1
  288. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
  289. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
  290. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
  291. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
  292. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-36377e679da2cd91.js +0 -1
  293. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
  294. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
  295. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
  296. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
  297. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
  298. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
  299. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
  300. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
  301. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
  302. /mage_ai/server/frontend_dist/_next/static/{vPsMu6Fi2zrHaf2fRXKRO → _krrrgup_C-dPOpX36S8I}/_ssgManifest.js +0 -0
  303. /mage_ai/server/frontend_dist_base_path_template/_next/static/{khKiaJtwrslgMmp4YSa1f → KLL5mirre9d7_ZeEpaw3s}/_ssgManifest.js +0 -0
  304. {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/LICENSE +0 -0
  305. {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/WHEEL +0 -0
  306. {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/entry_points.txt +0 -0
  307. {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/top_level.txt +0 -0
@@ -15,8 +15,10 @@ import yaml
15
15
  from jinja2 import Template
16
16
 
17
17
  from mage_ai.authentication.permissions.constants import EntityName
18
+ from mage_ai.cache.block import BlockCache
18
19
  from mage_ai.cache.pipeline import PipelineCache
19
20
  from mage_ai.data_preparation.models.block import Block, run_blocks, run_blocks_sync
21
+ from mage_ai.data_preparation.models.block.block_factory import BlockFactory
20
22
  from mage_ai.data_preparation.models.block.data_integration.utils import (
21
23
  convert_outputs_to_data,
22
24
  )
@@ -60,6 +62,8 @@ from mage_ai.data_preparation.shared.utils import get_template_vars
60
62
  from mage_ai.data_preparation.templates.utils import copy_template_directory
61
63
  from mage_ai.data_preparation.variable_manager import VariableManager
62
64
  from mage_ai.orchestration.constants import Entity
65
+ from mage_ai.orchestration.notification.config import NotificationConfig
66
+ from mage_ai.orchestration.notification.sender import NotificationSender
63
67
  from mage_ai.settings.platform import build_repo_path_for_all_projects
64
68
  from mage_ai.settings.platform.constants import project_platform_activated
65
69
  from mage_ai.settings.repo import get_repo_path
@@ -82,6 +86,8 @@ class Pipeline:
82
86
  repo_config=None,
83
87
  catalog=None,
84
88
  use_repo_path: bool = False,
89
+ description: str = None,
90
+ tags: List[str] = None,
85
91
  ):
86
92
  self.block_configs = []
87
93
  self.blocks_by_uuid = {}
@@ -90,7 +96,7 @@ class Pipeline:
90
96
  self.concurrency_config = dict()
91
97
  self.created_at = None
92
98
  self.data_integration = None
93
- self.description = None
99
+ self.description = description
94
100
  self.executor_config = dict()
95
101
  self.executor_type = None
96
102
  self.extensions = {}
@@ -101,7 +107,7 @@ class Pipeline:
101
107
  self.run_pipeline_in_one_process = False
102
108
  self.schedules = []
103
109
  self.settings = {}
104
- self.tags = []
110
+ self.tags = tags or []
105
111
  self.type = PipelineType.PYTHON
106
112
  self.use_repo_path = use_repo_path
107
113
  self.uuid = uuid
@@ -215,7 +221,14 @@ class Pipeline:
215
221
  self.widget_configs
216
222
 
217
223
  @classmethod
218
- def create(self, name, pipeline_type=PipelineType.PYTHON, repo_path=None):
224
+ def create(
225
+ self,
226
+ name: str,
227
+ description: str = None,
228
+ pipeline_type: PipelineType = PipelineType.PYTHON,
229
+ repo_path: str = None,
230
+ tags: List[str] = None,
231
+ ):
219
232
  """
220
233
  1. Create a new folder for pipeline
221
234
  2. Create a new yaml file to store pipeline config
@@ -231,14 +244,20 @@ class Pipeline:
231
244
  with open(os.path.join(pipeline_path, PIPELINE_CONFIG_FILE), 'w') as fp:
232
245
  yaml.dump(dict(
233
246
  created_at=str(datetime.now(tz=pytz.UTC)),
247
+ description=description,
234
248
  name=name,
249
+ tags=tags or [],
235
250
  uuid=uuid,
236
251
  type=format_enum(pipeline_type or PipelineType.PYTHON),
237
252
  ), fp)
253
+
238
254
  pipeline = Pipeline(
239
255
  uuid,
256
+ description=description,
240
257
  repo_path=repo_path,
258
+ tags=tags or [],
241
259
  )
260
+
242
261
  return pipeline
243
262
 
244
263
  @classmethod
@@ -322,7 +341,7 @@ class Pipeline:
322
341
  duplicate_pipeline_dict['name'] = duplicate_pipeline_uuid
323
342
  safe_write(
324
343
  duplicate_pipeline.config_path,
325
- yaml.dump(duplicate_pipeline_dict)
344
+ yaml.dump(duplicate_pipeline_dict),
326
345
  )
327
346
 
328
347
  tags = duplicate_pipeline_dict.get('tags')
@@ -368,6 +387,54 @@ class Pipeline:
368
387
  IntegrationPipeline,
369
388
  )
370
389
 
390
+ config_path, repo_path = self._get_config_path(
391
+ uuid,
392
+ repo_path=repo_path,
393
+ all_projects=all_projects,
394
+ use_repo_path=use_repo_path,
395
+ )
396
+
397
+ if check_if_exists and not os.path.exists(config_path):
398
+ return None
399
+
400
+ pipeline = self(uuid, repo_path=repo_path, use_repo_path=use_repo_path)
401
+ if PipelineType.INTEGRATION == pipeline.type:
402
+ pipeline = IntegrationPipeline(uuid, repo_path=repo_path)
403
+
404
+ return pipeline
405
+
406
+ @classmethod
407
+ def get_config(
408
+ self,
409
+ uuid,
410
+ repo_path: str = None,
411
+ all_projects: bool = False,
412
+ use_repo_path: bool = False,
413
+ ):
414
+ config_path, _ = self._get_config_path(
415
+ uuid,
416
+ repo_path=repo_path,
417
+ all_projects=all_projects,
418
+ use_repo_path=use_repo_path,
419
+ )
420
+
421
+ metadata_path = os.path.join(config_path, PIPELINE_CONFIG_FILE)
422
+
423
+ if not os.path.exists(metadata_path):
424
+ return None
425
+
426
+ with open(metadata_path) as fp:
427
+ config = yaml.full_load(fp) or {}
428
+ return config
429
+
430
+ @classmethod
431
+ def _get_config_path(
432
+ self,
433
+ uuid,
434
+ repo_path: str = None,
435
+ all_projects: bool = False,
436
+ use_repo_path: bool = False,
437
+ ) -> Tuple[str, str]:
371
438
  if all_projects and not use_repo_path and project_platform_activated():
372
439
  from mage_ai.settings.platform.utils import get_pipeline_config_path
373
440
 
@@ -379,15 +446,7 @@ class Pipeline:
379
446
  PIPELINES_FOLDER,
380
447
  uuid,
381
448
  )
382
-
383
- if check_if_exists and not os.path.exists(config_path):
384
- return None
385
-
386
- pipeline = self(uuid, repo_path=repo_path, use_repo_path=use_repo_path)
387
- if PipelineType.INTEGRATION == pipeline.type:
388
- pipeline = IntegrationPipeline(uuid, repo_path=repo_path)
389
-
390
- return pipeline
449
+ return config_path, repo_path
391
450
 
392
451
  @classmethod
393
452
  async def load_metadata(
@@ -457,7 +516,7 @@ class Pipeline:
457
516
 
458
517
  if not os.path.exists(config_path):
459
518
  raise Exception(f'Pipeline {uuid} does not exist.')
460
- async with aiofiles.open(config_path, mode='r') as f:
519
+ async with aiofiles.open(config_path, mode='r', encoding='utf-8') as f:
461
520
  config = yaml.safe_load(await f.read()) or {}
462
521
 
463
522
  if PipelineType.INTEGRATION == config.get('type'):
@@ -616,6 +675,7 @@ class Pipeline:
616
675
  analyze_outputs: bool = False,
617
676
  build_block_output_stdout: Callable[..., object] = None,
618
677
  global_vars=None,
678
+ retry_config=None,
619
679
  run_sensors: bool = True,
620
680
  run_tests: bool = True,
621
681
  update_status: bool = True,
@@ -632,6 +692,7 @@ class Pipeline:
632
692
  StreamingPipelineExecutor(self).execute(
633
693
  build_block_output_stdout=build_block_output_stdout,
634
694
  global_vars=global_vars,
695
+ retry_config=retry_config,
635
696
  )
636
697
  else:
637
698
  root_blocks = []
@@ -658,7 +719,7 @@ class Pipeline:
658
719
  def get_config_from_yaml(self):
659
720
  if not os.path.exists(self.config_path):
660
721
  raise Exception(f'Pipeline {self.uuid} does not exist in repo_path {self.repo_path}.')
661
- with open(self.config_path) as fp:
722
+ with open(self.config_path, encoding='utf-8') as fp:
662
723
  config = yaml.full_load(fp) or {}
663
724
  return config
664
725
 
@@ -669,6 +730,16 @@ class Pipeline:
669
730
  config = json.load(f)
670
731
  return config
671
732
 
733
+ def get_notification_sender(self):
734
+ return NotificationSender(
735
+ NotificationConfig.load(
736
+ config=merge_dict(
737
+ self.repo_config.notification_config,
738
+ self.notification_config,
739
+ ),
740
+ ),
741
+ )
742
+
672
743
  def load_config_from_yaml(self):
673
744
  catalog = None
674
745
  if os.path.exists(self.catalog_config_path):
@@ -717,7 +788,8 @@ class Pipeline:
717
788
  )
718
789
 
719
790
  language = c.get('language')
720
- return Block.block_class_from_type(block_type, language=language, pipeline=self)(
791
+
792
+ return BlockFactory.block_class_from_type(block_type, language=language, pipeline=self)(
721
793
  c.get('name'),
722
794
  c.get('uuid'),
723
795
  block_type,
@@ -931,6 +1003,8 @@ class Pipeline:
931
1003
  include_outputs=include_outputs,
932
1004
  sample_count=sample_count,
933
1005
  )
1006
+ if include_block_pipelines:
1007
+ shared_kwargs['block_cache'] = BlockCache()
934
1008
  blocks_data = await asyncio.gather(
935
1009
  *[b.to_dict_async(**merge_dict(shared_kwargs, dict(
936
1010
  include_block_catalog=include_block_catalog,
@@ -991,6 +1065,7 @@ class Pipeline:
991
1065
  old_uuid = None
992
1066
  blocks_to_remove_from_cache = []
993
1067
  block_uuids_to_add_to_cache = []
1068
+ tags_to_remove_from_cache = []
994
1069
  should_update_block_cache = False
995
1070
  should_update_tag_cache = False
996
1071
 
@@ -1043,6 +1118,10 @@ class Pipeline:
1043
1118
  old_tags = self.tags or []
1044
1119
 
1045
1120
  if sorted(new_tags) != sorted(old_tags):
1121
+ tags_diff = set(old_tags).symmetric_difference(set(new_tags))
1122
+ for tag in tags_diff:
1123
+ if tag in old_tags:
1124
+ tags_to_remove_from_cache.append(tag)
1046
1125
  self.tags = new_tags
1047
1126
  should_save = True
1048
1127
  should_update_tag_cache = True
@@ -1229,7 +1308,9 @@ class Pipeline:
1229
1308
  file_path = (configuration.get('file_source') or {}).get('path')
1230
1309
  if file_path:
1231
1310
  # Check for block name with period to avoid replacing a directory name
1232
- new_file_path = file_path.replace(f'{block.name}.', f'{name}.')
1311
+ new_file_path = file_path.replace(
1312
+ f'{clean_name(block.name)}.', f'{clean_name(name)}.'
1313
+ )
1233
1314
  configuration['file_source']['path'] = new_file_path
1234
1315
  block_update_payload['configuration'] = configuration
1235
1316
  blocks_to_remove_from_cache.append(block.to_dict())
@@ -1296,6 +1377,8 @@ class Pipeline:
1296
1377
 
1297
1378
  cache = await TagCache.initialize_cache()
1298
1379
 
1380
+ for tag_uuid in tags_to_remove_from_cache:
1381
+ cache.remove_pipeline(tag_uuid, self.uuid, self.repo_path)
1299
1382
  for tag_uuid in self.tags:
1300
1383
  if old_uuid:
1301
1384
  cache.remove_pipeline(tag_uuid, old_uuid, self.repo_path)
@@ -2065,7 +2148,7 @@ class Pipeline:
2065
2148
  'Blocks cannot be added or removed when saving content, please try again.',
2066
2149
  )
2067
2150
 
2068
- content = yaml.dump(pipeline_dict)
2151
+ content = yaml.dump(pipeline_dict, allow_unicode=True)
2069
2152
 
2070
2153
  safe_write(self.config_path, content)
2071
2154
 
@@ -2138,7 +2221,7 @@ class Pipeline:
2138
2221
  'Blocks cannot be added or removed when saving content, please try again.',
2139
2222
  )
2140
2223
 
2141
- content = yaml.dump(pipeline_dict)
2224
+ content = yaml.dump(pipeline_dict, allow_unicode=True)
2142
2225
 
2143
2226
  test_path = f'{self.config_path}.test'
2144
2227
  async with aiofiles.open(test_path, mode='w', encoding='utf-8') as fp:
@@ -19,6 +19,12 @@ STRING_SERIALIZABLE_COLUMN_TYPES = set([
19
19
  'ObjectId',
20
20
  ])
21
21
 
22
+ AMBIGUOUS_COLUMN_TYPES = set([
23
+ 'mixed-integer',
24
+ 'complex',
25
+ 'unknown-array',
26
+ ])
27
+
22
28
  CAST_TYPE_COLUMN_TYPES = set([
23
29
  'Int64',
24
30
  'int64',
@@ -7,7 +7,7 @@ from typing import Any, Dict, List
7
7
  import numpy as np
8
8
  import pandas as pd
9
9
  import polars as pl
10
- from pandas.api.types import is_object_dtype
10
+ from pandas.api.types import infer_dtype, is_object_dtype
11
11
  from pandas.core.indexes.range import RangeIndex
12
12
 
13
13
  from mage_ai.data_cleaner.shared.utils import is_geo_dataframe, is_spark_dataframe
@@ -18,6 +18,7 @@ from mage_ai.data_preparation.models.constants import (
18
18
  VARIABLE_DIR,
19
19
  )
20
20
  from mage_ai.data_preparation.models.utils import ( # dask_from_pandas,
21
+ AMBIGUOUS_COLUMN_TYPES,
21
22
  STRING_SERIALIZABLE_COLUMN_TYPES,
22
23
  apply_transform_pandas,
23
24
  cast_column_types,
@@ -282,7 +283,9 @@ class Variable:
282
283
  else:
283
284
  self.__write_json(data)
284
285
 
285
- self.write_metadata()
286
+ if self.variable_type != VariableType.SPARK_DATAFRAME:
287
+ # Not write json file in spark data directory to avoid read error
288
+ self.write_metadata()
286
289
 
287
290
  async def write_data_async(self, data: Any) -> None:
288
291
  """
@@ -315,7 +318,9 @@ class Variable:
315
318
  else:
316
319
  await self.__write_json_async(data)
317
320
 
318
- self.write_metadata()
321
+ if self.variable_type != VariableType.SPARK_DATAFRAME:
322
+ # Not write json file in spark data directory to avoid read error
323
+ self.write_metadata()
319
324
 
320
325
  def write_metadata(self) -> None:
321
326
  """
@@ -578,10 +583,19 @@ class Variable:
578
583
  else:
579
584
  series_non_null = df_col.dropna()
580
585
  if len(series_non_null) > 0:
581
- coltype = type(series_non_null.iloc[0])
586
+ sample_element = series_non_null.iloc[0]
587
+ coltype = type(sample_element)
588
+ coltype_inferred = infer_dtype(series_non_null)
582
589
  if is_object_dtype(series_non_null.dtype):
583
590
  if coltype.__name__ in STRING_SERIALIZABLE_COLUMN_TYPES:
584
591
  cast_coltype = str
592
+ # If the column is a "primitive" type, i.e. int/bool/etc and there is
593
+ # a mix of types in the column, cast to string
594
+ elif (
595
+ not hasattr(sample_element, '__dict__')
596
+ and coltype_inferred in AMBIGUOUS_COLUMN_TYPES
597
+ ):
598
+ cast_coltype = str
585
599
  else:
586
600
  cast_coltype = coltype
587
601
  try:
@@ -310,8 +310,9 @@ def get_cluster_type(repo_path=None) -> Optional[ClusterType]:
310
310
 
311
311
  def set_project_uuid_from_metadata() -> None:
312
312
  global project_uuid
313
- if os.path.exists(get_metadata_path()):
314
- with open(get_metadata_path(), 'r', encoding='utf-8') as f:
313
+ metadata_path = get_metadata_path(root_project=True)
314
+ if os.path.exists(metadata_path):
315
+ with open(metadata_path, 'r', encoding='utf-8') as f:
315
316
  config = yml.load(f) or {}
316
317
  project_uuid = config.get('project_uuid')
317
318
 
@@ -25,7 +25,7 @@ def get_template_vars_no_db(include_python_libraries: Dict = None) -> Dict[str,
25
25
  try:
26
26
  from mage_ai.services.aws.secrets_manager.secrets_manager import get_secret
27
27
  kwargs['aws_secret_var'] = get_secret
28
- except ImportError:
28
+ except Exception:
29
29
  pass
30
30
 
31
31
  try:
@@ -148,7 +148,7 @@ class GCSStorage(BaseStorage):
148
148
  df.write_parquet(buffer)
149
149
  buffer.seek(0)
150
150
  blob = self.bucket.blob(gcs_url_path(file_path))
151
- blob.upload_from_string(buffer)
151
+ blob.upload_from_string(buffer.getvalue())
152
152
 
153
153
  @contextmanager
154
154
  def open_to_write(self, file_path: str) -> None:
@@ -608,6 +608,13 @@ TEMPLATES_ONLY_FOR_V2 = [
608
608
  name='MySQL',
609
609
  path='data_exporters/mysql.py',
610
610
  ),
611
+ dict(
612
+ block_type=BlockType.DATA_EXPORTER,
613
+ groups=[GROUP_DATABASES],
614
+ language=BlockLanguage.PYTHON,
615
+ name='OracleDB',
616
+ path='data_exporters/oracledb.py',
617
+ ),
611
618
  dict(
612
619
  block_type=BlockType.DATA_EXPORTER,
613
620
  groups=[GROUP_DATABASES],
@@ -23,8 +23,8 @@ def export_data_to_mysql(df: DataFrame, **kwargs) -> None:
23
23
  with MySQL.with_config(ConfigFileLoader(config_path, config_profile)) as loader:
24
24
  loader.export(
25
25
  df,
26
- None,
27
- table_name,
26
+ schema_name=None,
27
+ table_name=table_name,
28
28
  index=False, # Specifies whether to include index in exported table
29
29
  if_exists='replace', # Specify resolution policy if table name already exists
30
30
  )
@@ -0,0 +1,27 @@
1
+ from os import path
2
+
3
+ from pandas import DataFrame
4
+
5
+ from mage_ai.settings.repo import get_repo_path
6
+ from mage_ai.io.config import ConfigFileLoader
7
+ from mage_ai.io.oracledb import OracleDB
8
+
9
+ if 'data_exporter' not in globals():
10
+ from mage_ai.data_preparation.decorators import data_exporter
11
+
12
+
13
+ @data_exporter
14
+ def export_data_to_oracledb(df: DataFrame, **kwargs) -> None:
15
+ """
16
+ Template to export data to Oracledb.
17
+ """
18
+ config_path = path.join(get_repo_path(), 'io_config.yaml')
19
+ config_profile = 'default'
20
+ table_name = 'your_table_name'
21
+
22
+ with OracleDB.with_config(ConfigFileLoader(config_path, config_profile)) as exporter:
23
+ exporter.export(
24
+ df,
25
+ table_name=table_name,
26
+ if_exists='replace', # Specify resolution policy if table name already exists
27
+ )
@@ -43,6 +43,7 @@ spark_config:
43
43
  # e.g. kwargs['context']['spark'] = spark_session
44
44
  custom_session_var_name: 'spark'
45
45
 
46
+ help_improve_mage: true
46
47
  notification_config:
47
48
  alert_on:
48
49
  - trigger_failure