mage-ai 0.9.12__py3-none-any.whl → 0.9.14__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 (325) hide show
  1. mage_ai/ai/generator.py +1 -1
  2. mage_ai/ai/generator_cmds.py +1 -1
  3. mage_ai/ai/llm_pipeline_wizard.py +31 -17
  4. mage_ai/api/policies/BlockPolicy.py +1 -0
  5. mage_ai/api/policies/PipelineRunPolicy.py +1 -0
  6. mage_ai/api/policies/PipelineSchedulePolicy.py +12 -0
  7. mage_ai/api/policies/TagPolicy.py +18 -0
  8. mage_ai/api/presenters/BlockRunPresenter.py +4 -1
  9. mage_ai/api/presenters/PipelineRunPresenter.py +2 -0
  10. mage_ai/api/presenters/PipelineSchedulePresenter.py +9 -2
  11. mage_ai/api/presenters/TagPresenter.py +3 -0
  12. mage_ai/api/resources/BackfillResource.py +6 -3
  13. mage_ai/api/resources/BlockResource.py +2 -0
  14. mage_ai/api/resources/BlockRunResource.py +18 -12
  15. mage_ai/api/resources/DatabaseResource.py +23 -0
  16. mage_ai/api/resources/GitBranchResource.py +8 -1
  17. mage_ai/api/resources/GlobalDataProductResource.py +5 -2
  18. mage_ai/api/resources/PipelineResource.py +30 -14
  19. mage_ai/api/resources/PipelineScheduleResource.py +157 -1
  20. mage_ai/api/resources/SearchResultResource.py +1 -0
  21. mage_ai/api/resources/TagResource.py +16 -3
  22. mage_ai/data_integrations/sources/constants.py +1 -0
  23. mage_ai/data_preparation/git/__init__.py +18 -0
  24. mage_ai/data_preparation/models/block/__init__.py +34 -11
  25. mage_ai/data_preparation/models/block/dbt/utils/__init__.py +37 -10
  26. mage_ai/data_preparation/models/block/integration/__init__.py +1 -1
  27. mage_ai/data_preparation/models/block/sql/__init__.py +44 -2
  28. mage_ai/data_preparation/models/custom_templates/utils.py +14 -4
  29. mage_ai/data_preparation/models/global_data_product/__init__.py +8 -0
  30. mage_ai/data_preparation/models/pipeline.py +4 -0
  31. mage_ai/data_preparation/models/variable.py +5 -2
  32. mage_ai/data_preparation/repo_manager.py +28 -16
  33. mage_ai/io/clickhouse.py +9 -6
  34. mage_ai/io/redshift.py +9 -10
  35. mage_ai/io/utils.py +3 -1
  36. mage_ai/orchestration/db/migrations/README.md +39 -2
  37. mage_ai/orchestration/db/migrations/env.py +1 -0
  38. mage_ai/orchestration/db/migrations/versions/386bcfebd48d_create_tag_and_tagassociation_tables.py +59 -0
  39. mage_ai/orchestration/db/models/schedules.py +29 -2
  40. mage_ai/orchestration/db/models/tags.py +57 -0
  41. mage_ai/orchestration/pipeline_scheduler.py +7 -7
  42. mage_ai/orchestration/triggers/global_data_product.py +41 -40
  43. mage_ai/orchestration/triggers/utils.py +11 -1
  44. mage_ai/server/constants.py +1 -1
  45. mage_ai/server/frontend_dist/404.html +2 -2
  46. mage_ai/server/frontend_dist/404.html.html +2 -2
  47. mage_ai/server/frontend_dist/_next/static/CNjkRIWPaAu1yJUmIaX_q/_buildManifest.js +1 -0
  48. mage_ai/server/frontend_dist/_next/static/chunks/1005-a2f0e3ee378ef02b.js +1 -0
  49. mage_ai/server/frontend_dist/_next/static/chunks/1424-fca78f21a81a7183.js +1 -0
  50. mage_ai/server/frontend_dist/_next/static/chunks/1484-87d4d4a698ac63dc.js +1 -0
  51. mage_ai/server/frontend_dist/_next/static/chunks/2485-39885e5335888821.js +1 -0
  52. mage_ai/server/frontend_dist/_next/static/chunks/2786-f71862671f66d948.js +1 -0
  53. mage_ai/server/frontend_dist/_next/static/chunks/3391-6f0a0a5c254cd7f2.js +1 -0
  54. mage_ai/server/frontend_dist/_next/static/chunks/3881-131cf690e54c23a3.js +1 -0
  55. mage_ai/server/frontend_dist/_next/static/chunks/437-331193bd9b2fe777.js +1 -0
  56. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4822-045cc7cdd7c95163.js → frontend_dist/_next/static/chunks/4822-ee62acb1927c8150.js} +1 -1
  57. mage_ai/server/frontend_dist/_next/static/chunks/547-bd961ea93f3eb98b.js +1 -0
  58. mage_ai/server/frontend_dist/_next/static/chunks/6299-fcb702d0f3d3291b.js +1 -0
  59. mage_ai/server/frontend_dist/_next/static/chunks/6422-0cdd6e596dcd43b6.js +1 -0
  60. mage_ai/server/frontend_dist/_next/static/chunks/{6786-77c7e36678abb2c6.js → 6786-55e1bca3c897d5ee.js} +1 -1
  61. mage_ai/server/frontend_dist/_next/static/chunks/7496-7e4dd11e3f3b8e79.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/7722-76c724a66240561b.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/7815-8b68b0eb665fcd2d.js +1 -0
  64. mage_ai/server/frontend_dist/_next/static/chunks/8190-d38ed1133030797d.js +1 -0
  65. mage_ai/server/frontend_dist/_next/static/chunks/8952-9d6fa18fa9378989.js +1 -0
  66. mage_ai/server/frontend_dist/_next/static/chunks/9605-9332e1686c46da7d.js +1 -0
  67. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-9dae6fa5126cf001.js +1 -0
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-2dc2a0dfc0ff620d.js +1 -0
  69. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-6d3d53624debede6.js +1 -0
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-2756fe6d9decae4a.js +1 -0
  71. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-6577159a0af52a78.js +1 -0
  72. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-6815a3ece7dc1678.js +1 -0
  73. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-7f790238fe70d9ab.js +1 -0
  74. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipeline-runs-33c7f2550add0719.js +1 -0
  75. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-07e4a3a674e83578.js +1 -0
  76. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-b8b4bed1e8e50068.js +1 -0
  77. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-54cb4936accdd2d9.js +1 -0
  78. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-d331e98ad103b13e.js +1 -0
  79. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-d87d0c21758a2d7c.js +1 -0
  80. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-68e1b861ef4fc0d7.js +1 -0
  81. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-9fa0c4ce1c921a41.js +1 -0
  82. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-d5ef19ca1f9931de.js +1 -0
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-4a2671811a153411.js +1 -0
  84. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-8872a6e00280f58c.js +1 -0
  85. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-484581ae34a1c596.js +1 -0
  86. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-ce11db27e4af7869.js +1 -0
  87. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-624a2d7cbe6303b4.js +1 -0
  88. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-1169f4eecf752033.js +1 -0
  89. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-d2224a447987fa69.js → frontend_dist/_next/static/chunks/pages/settings/account/profile-c3ff06a12baa40a2.js} +1 -1
  90. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-60b4398d7ae00206.js +1 -0
  91. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-dd827816bf4a7908.js → frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-05b53444f0e7449b.js} +1 -1
  92. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-097aa0bef1e34cdb.js → frontend_dist/_next/static/chunks/pages/sign-in-a5e9561a6c0d2e38.js} +1 -1
  93. mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/{[...slug]-78a07e7fe8973811.js → [...slug]-c21b269750441494.js} +1 -1
  94. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/templates-19df643f52679d5a.js → frontend_dist/_next/static/chunks/pages/templates-ce2a29d477a6ce94.js} +1 -1
  95. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-71bbb30dd9b57f80.js +1 -0
  96. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-1dc780d52fbd1573.js +1 -0
  97. mage_ai/server/frontend_dist/files.html +2 -2
  98. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  99. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  100. mage_ai/server/frontend_dist/index.html +2 -2
  101. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  102. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  103. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  104. mage_ai/server/frontend_dist/manage/users.html +2 -2
  105. mage_ai/server/frontend_dist/manage.html +2 -2
  106. mage_ai/server/frontend_dist/overview.html +2 -2
  107. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  108. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  109. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  110. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  111. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  112. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  113. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  114. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  115. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  116. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  117. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  118. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  119. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  120. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  121. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  122. mage_ai/server/frontend_dist/pipelines.html +2 -2
  123. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  124. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  125. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  126. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  127. mage_ai/server/frontend_dist/settings.html +2 -2
  128. mage_ai/server/frontend_dist/sign-in.html +11 -11
  129. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  130. mage_ai/server/frontend_dist/templates.html +2 -2
  131. mage_ai/server/frontend_dist/terminal.html +2 -2
  132. mage_ai/server/frontend_dist/test.html +3 -3
  133. mage_ai/server/frontend_dist/triggers.html +2 -2
  134. mage_ai/server/frontend_dist/version-control.html +2 -2
  135. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  136. mage_ai/server/frontend_dist_base_path_template/404.html.html +2 -2
  137. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1005-a2f0e3ee378ef02b.js +1 -0
  138. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1424-fca78f21a81a7183.js +1 -0
  139. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1484-87d4d4a698ac63dc.js +1 -0
  140. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2485-39885e5335888821.js +1 -0
  141. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2786-f71862671f66d948.js +1 -0
  142. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3391-6f0a0a5c254cd7f2.js +1 -0
  143. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3881-131cf690e54c23a3.js +1 -0
  144. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/437-331193bd9b2fe777.js +1 -0
  145. mage_ai/server/{frontend_dist/_next/static/chunks/4822-045cc7cdd7c95163.js → frontend_dist_base_path_template/_next/static/chunks/4822-ee62acb1927c8150.js} +1 -1
  146. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/547-bd961ea93f3eb98b.js +1 -0
  147. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6299-fcb702d0f3d3291b.js +1 -0
  148. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6422-0cdd6e596dcd43b6.js +1 -0
  149. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{6786-77c7e36678abb2c6.js → 6786-55e1bca3c897d5ee.js} +1 -1
  150. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7496-7e4dd11e3f3b8e79.js +1 -0
  151. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7722-76c724a66240561b.js +1 -0
  152. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7815-8b68b0eb665fcd2d.js +1 -0
  153. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8190-d38ed1133030797d.js +1 -0
  154. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8952-9d6fa18fa9378989.js +1 -0
  155. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9605-9332e1686c46da7d.js +1 -0
  156. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-9dae6fa5126cf001.js +1 -0
  157. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-2dc2a0dfc0ff620d.js +1 -0
  158. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-6d3d53624debede6.js +1 -0
  159. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-2756fe6d9decae4a.js +1 -0
  160. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-6577159a0af52a78.js +1 -0
  161. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-6815a3ece7dc1678.js +1 -0
  162. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-7f790238fe70d9ab.js +1 -0
  163. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-33c7f2550add0719.js +1 -0
  164. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-07e4a3a674e83578.js +1 -0
  165. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-b8b4bed1e8e50068.js +1 -0
  166. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-54cb4936accdd2d9.js +1 -0
  167. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-d331e98ad103b13e.js +1 -0
  168. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-d87d0c21758a2d7c.js +1 -0
  169. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-68e1b861ef4fc0d7.js +1 -0
  170. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-9fa0c4ce1c921a41.js +1 -0
  171. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-d5ef19ca1f9931de.js +1 -0
  172. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-4a2671811a153411.js +1 -0
  173. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-8872a6e00280f58c.js +1 -0
  174. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-484581ae34a1c596.js +1 -0
  175. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-ce11db27e4af7869.js +1 -0
  176. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-624a2d7cbe6303b4.js +1 -0
  177. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-1169f4eecf752033.js +1 -0
  178. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/account/profile-d2224a447987fa69.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-c3ff06a12baa40a2.js} +1 -1
  179. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-60b4398d7ae00206.js +1 -0
  180. mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-dd827816bf4a7908.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-05b53444f0e7449b.js} +1 -1
  181. mage_ai/server/{frontend_dist/_next/static/chunks/pages/sign-in-097aa0bef1e34cdb.js → frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-a5e9561a6c0d2e38.js} +1 -1
  182. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/{[...slug]-78a07e7fe8973811.js → [...slug]-c21b269750441494.js} +1 -1
  183. mage_ai/server/{frontend_dist/_next/static/chunks/pages/templates-19df643f52679d5a.js → frontend_dist_base_path_template/_next/static/chunks/pages/templates-ce2a29d477a6ce94.js} +1 -1
  184. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-71bbb30dd9b57f80.js +1 -0
  185. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-1dc780d52fbd1573.js +1 -0
  186. mage_ai/server/frontend_dist_base_path_template/_next/static/yJvL-3bfsNF3WCStZ10Dm/_buildManifest.js +1 -0
  187. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  188. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  191. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  192. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  193. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  194. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  195. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  196. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  197. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  198. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  199. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  200. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  201. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  202. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  203. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  204. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  205. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  206. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  207. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  208. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  209. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  210. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  211. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  212. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  213. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  214. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  215. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  216. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  217. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  218. mage_ai/server/frontend_dist_base_path_template/sign-in.html +11 -11
  219. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  220. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  221. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  222. mage_ai/server/frontend_dist_base_path_template/test.html +3 -3
  223. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  224. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  225. mage_ai/server/server.py +53 -27
  226. mage_ai/services/spark/spark.py +75 -2
  227. mage_ai/streaming/constants.py +1 -0
  228. mage_ai/streaming/sources/kafka.py +17 -9
  229. mage_ai/tests/data_preparation/models/custom_templates/__init__.py +0 -0
  230. mage_ai/tests/data_preparation/models/custom_templates/test_utils.py +36 -0
  231. mage_ai/tests/data_preparation/models/test_block.py +48 -0
  232. mage_ai/tests/data_preparation/test_repo_manager.py +19 -1
  233. mage_ai/tests/server/test_server.py +20 -2
  234. mage_ai/tests/services/spark/__init__.py +0 -0
  235. mage_ai/tests/services/spark/test_spark.py +52 -0
  236. {mage_ai-0.9.12.dist-info → mage_ai-0.9.14.dist-info}/METADATA +1 -1
  237. {mage_ai-0.9.12.dist-info → mage_ai-0.9.14.dist-info}/RECORD +245 -233
  238. mage_ai/server/frontend_dist/_next/static/RdDEYzOW6lfmOEilKsz4V/_buildManifest.js +0 -1
  239. mage_ai/server/frontend_dist/_next/static/chunks/1005-2f8ef0e28c917767.js +0 -1
  240. mage_ai/server/frontend_dist/_next/static/chunks/1424-a2cd1bfc708a323b.js +0 -1
  241. mage_ai/server/frontend_dist/_next/static/chunks/1484-a07f74ae5c40141c.js +0 -1
  242. mage_ai/server/frontend_dist/_next/static/chunks/2485-b569baad92049d6b.js +0 -1
  243. mage_ai/server/frontend_dist/_next/static/chunks/2786-acce6ea0d9b4898e.js +0 -1
  244. mage_ai/server/frontend_dist/_next/static/chunks/3654-14ee3eacc42b118a.js +0 -1
  245. mage_ai/server/frontend_dist/_next/static/chunks/3881-0eb04f7f7a244347.js +0 -1
  246. mage_ai/server/frontend_dist/_next/static/chunks/437-d43ccff3a064a528.js +0 -1
  247. mage_ai/server/frontend_dist/_next/static/chunks/547-4ad2cdae967055b6.js +0 -1
  248. mage_ai/server/frontend_dist/_next/static/chunks/6299-cf188c1b7a1bc33c.js +0 -1
  249. mage_ai/server/frontend_dist/_next/static/chunks/7496-ab1be388ae09d362.js +0 -1
  250. mage_ai/server/frontend_dist/_next/static/chunks/7722-a74e6f977993e75e.js +0 -1
  251. mage_ai/server/frontend_dist/_next/static/chunks/7815-fbd99c8f259d9e8b.js +0 -1
  252. mage_ai/server/frontend_dist/_next/static/chunks/8952-98e54b14c1af492f.js +0 -1
  253. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-74805cf1296fd50f.js +0 -1
  254. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-bcdaa82adcca891d.js +0 -1
  255. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-abdbda772d94c386.js +0 -1
  256. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-01f8ef10e87ec236.js +0 -1
  257. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-950fbcb72961eb3c.js +0 -1
  258. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-c6fd44191c812edf.js +0 -1
  259. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-6e46ed84cf3f4e9d.js +0 -1
  260. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipeline-runs-1d52bba72442c53f.js +0 -1
  261. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-8c33956a28fb4fa8.js +0 -1
  262. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-b28d151c32c2a469.js +0 -1
  263. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1708e5576cd26d1.js +0 -1
  264. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-0f3468d52020dcbf.js +0 -1
  265. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-489d02937d5f4695.js +0 -1
  266. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-544475d8e841638f.js +0 -1
  267. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e117a99f334b6022.js +0 -1
  268. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-f1ef481c7beb8aef.js +0 -1
  269. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-ab52e3174c3dcf64.js +0 -1
  270. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-3e290f7d76c68b3f.js +0 -1
  271. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-1ac4dc91ec394c6d.js +0 -1
  272. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-4753de69f7e366c5.js +0 -1
  273. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cf285c43759e9b2a.js +0 -1
  274. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3f86e7f1c8d63beb.js +0 -1
  275. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-b2354688508b0755.js +0 -1
  276. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-cacb24e3632cfdfc.js +0 -1
  277. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5a6e3a62fef551f1.js +0 -1
  278. mage_ai/server/frontend_dist_base_path_template/_next/static/4dbzHNz2XwS_s6Z0qsIGO/_buildManifest.js +0 -1
  279. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1005-2f8ef0e28c917767.js +0 -1
  280. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1424-a2cd1bfc708a323b.js +0 -1
  281. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1484-a07f74ae5c40141c.js +0 -1
  282. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2485-b569baad92049d6b.js +0 -1
  283. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2786-acce6ea0d9b4898e.js +0 -1
  284. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3654-14ee3eacc42b118a.js +0 -1
  285. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3881-0eb04f7f7a244347.js +0 -1
  286. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/437-d43ccff3a064a528.js +0 -1
  287. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/547-4ad2cdae967055b6.js +0 -1
  288. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6299-cf188c1b7a1bc33c.js +0 -1
  289. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7496-ab1be388ae09d362.js +0 -1
  290. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7722-a74e6f977993e75e.js +0 -1
  291. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7815-fbd99c8f259d9e8b.js +0 -1
  292. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8952-98e54b14c1af492f.js +0 -1
  293. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-74805cf1296fd50f.js +0 -1
  294. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-bcdaa82adcca891d.js +0 -1
  295. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-abdbda772d94c386.js +0 -1
  296. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-01f8ef10e87ec236.js +0 -1
  297. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-950fbcb72961eb3c.js +0 -1
  298. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-c6fd44191c812edf.js +0 -1
  299. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-6e46ed84cf3f4e9d.js +0 -1
  300. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-1d52bba72442c53f.js +0 -1
  301. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-8c33956a28fb4fa8.js +0 -1
  302. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-b28d151c32c2a469.js +0 -1
  303. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1708e5576cd26d1.js +0 -1
  304. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-0f3468d52020dcbf.js +0 -1
  305. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-489d02937d5f4695.js +0 -1
  306. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-544475d8e841638f.js +0 -1
  307. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e117a99f334b6022.js +0 -1
  308. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-f1ef481c7beb8aef.js +0 -1
  309. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-ab52e3174c3dcf64.js +0 -1
  310. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-3e290f7d76c68b3f.js +0 -1
  311. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-1ac4dc91ec394c6d.js +0 -1
  312. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-4753de69f7e366c5.js +0 -1
  313. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cf285c43759e9b2a.js +0 -1
  314. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3f86e7f1c8d63beb.js +0 -1
  315. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-b2354688508b0755.js +0 -1
  316. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-cacb24e3632cfdfc.js +0 -1
  317. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5a6e3a62fef551f1.js +0 -1
  318. /mage_ai/server/frontend_dist/_next/static/{RdDEYzOW6lfmOEilKsz4V → CNjkRIWPaAu1yJUmIaX_q}/_middlewareManifest.js +0 -0
  319. /mage_ai/server/frontend_dist/_next/static/{RdDEYzOW6lfmOEilKsz4V → CNjkRIWPaAu1yJUmIaX_q}/_ssgManifest.js +0 -0
  320. /mage_ai/server/frontend_dist_base_path_template/_next/static/{4dbzHNz2XwS_s6Z0qsIGO → yJvL-3bfsNF3WCStZ10Dm}/_middlewareManifest.js +0 -0
  321. /mage_ai/server/frontend_dist_base_path_template/_next/static/{4dbzHNz2XwS_s6Z0qsIGO → yJvL-3bfsNF3WCStZ10Dm}/_ssgManifest.js +0 -0
  322. {mage_ai-0.9.12.dist-info → mage_ai-0.9.14.dist-info}/LICENSE +0 -0
  323. {mage_ai-0.9.12.dist-info → mage_ai-0.9.14.dist-info}/WHEEL +0 -0
  324. {mage_ai-0.9.12.dist-info → mage_ai-0.9.14.dist-info}/entry_points.txt +0 -0
  325. {mage_ai-0.9.12.dist-info → mage_ai-0.9.14.dist-info}/top_level.txt +0 -0
mage_ai/ai/generator.py CHANGED
@@ -33,7 +33,7 @@ class Generator:
33
33
  elif use_case == LLMUseCase.GENERATE_PIPELINE_WITH_DESCRIPTION:
34
34
  from mage_ai.ai.llm_pipeline_wizard import LLMPipelineWizard
35
35
 
36
- return await LLMPipelineWizard().async_generate_pipeline_with_description(
36
+ return await LLMPipelineWizard().async_generate_pipeline_from_description(
37
37
  request.get('pipeline_description'),
38
38
  )
39
39
  elif use_case == LLMUseCase.GENERATE_COMMENT_FOR_CODE:
@@ -49,7 +49,7 @@ def generate_block_with_description(block_description: str):
49
49
 
50
50
  @app.command()
51
51
  def generate_pipeline_with_description(pipeline_description: str):
52
- print(asyncio.run(LLMPipelineWizard().async_generate_pipeline_with_description(
52
+ print(asyncio.run(LLMPipelineWizard().async_generate_pipeline_from_description(
53
53
  pipeline_description)))
54
54
 
55
55
 
@@ -2,6 +2,7 @@ import ast
2
2
  import asyncio
3
3
  import json
4
4
  import os
5
+ import re
5
6
  from typing import Dict
6
7
 
7
8
  import openai
@@ -53,23 +54,24 @@ PROMPT_TO_SPLIT_BLOCKS = """
53
54
  A BLOCK does one action either reading data from one data source, transforming the data from
54
55
  one format to another or exporting data into a data source.
55
56
  Based on the code description delimited by triple backticks, your task is to identify
56
- how many BLOCKS required and function for each BLOCK.
57
+ how many BLOCKS required, function for each BLOCK and upstream blocks between BLOCKs.
57
58
 
58
59
  Use the following format:
59
- BLOCK 1: <block function>
60
- BLOCK 2: <block function>
61
- BLOCK 3: <block function>
60
+ BLOCK 1: function: <block function>. upstream: <upstream blocks>
61
+ BLOCK 2: function: <block function>. upstream: <upstream blocks>
62
+ BLOCK 3: function: <block function>. upstream: <upstream blocks>
62
63
  ...
63
64
 
64
65
  Example:
65
66
  <code description>: ```
66
- Read data from MySQL, filter out rows with book_price > 100, and save data to BigQuery.
67
+ Read data from MySQL and Postgres, filter out rows with book_price > 100, and save data to BigQuery.
67
68
  ```
68
69
 
69
70
  Answer:
70
- BLOCK 1: load data from MySQL
71
- BLOCK 2: filter out rows with book_price > 100
72
- BLOCK 3: export data to BigQuery
71
+ BLOCK 1: function: load data from MySQL. upstream:
72
+ BLOCK 2: function: load data from Postgres. upstream:
73
+ BLOCK 3: function: filter out rows with book_price > 100. upstream: 1, 2
74
+ BLOCK 4: function: export data to BigQuery. upstream: 3
73
75
 
74
76
  <code description>: ```{code_description}```"""
75
77
  PROMPT_FOR_FUNCTION_COMMENT = """
@@ -81,6 +83,7 @@ Your task is to write comments for each function inside.
81
83
  The comment should follow Google Docstring format.
82
84
  Return your response in JSON format with function name as key and the comment as value.
83
85
  """
86
+ BLOCK_SPLIT_PATTERN = r"BLOCK\s+(\w+):\s+function:\s+(.*?)\.\s+upstream:\s*(.*?)$"
84
87
  TRANSFORMERS_FOLDER = 'transformers'
85
88
  CLASSIFICATION_FUNCTION_NAME = "classify_description"
86
89
  TEMPLATE_CLASSIFICATION_FUNCTION = [
@@ -197,7 +200,10 @@ class LLMPipelineWizard:
197
200
  function_args.get(DataSource.__name__))
198
201
  return block_type, block_language, pipeline_type, config
199
202
 
200
- async def async_generate_block_with_description(self, block_description: str) -> dict:
203
+ async def async_generate_block_with_description(
204
+ self,
205
+ block_description: str,
206
+ upstream_blocks: [str]) -> dict:
201
207
  messages = [{"role": "user", "content": block_description}]
202
208
  response = await openai.ChatCompletion.acreate(
203
209
  model="gpt-3.5-turbo-0613",
@@ -220,6 +226,7 @@ class LLMPipelineWizard:
220
226
  pipeline_type=pipeline_type,
221
227
  ),
222
228
  language=block_language,
229
+ upstream_blocks=upstream_blocks,
223
230
  )
224
231
  else:
225
232
  logger.error("Failed to interpret the description as a block template.")
@@ -238,11 +245,12 @@ class LLMPipelineWizard:
238
245
  async def __async_generate_blocks(self,
239
246
  block_dict: dict,
240
247
  block_id: int,
241
- block_description: str) -> dict:
242
- block = await self.async_generate_block_with_description(block_description)
248
+ block_description: str,
249
+ upstream_blocks: [str]) -> dict:
250
+ block = await self.async_generate_block_with_description(block_description, upstream_blocks)
243
251
  block_dict[block_id] = block
244
252
 
245
- async def async_generate_pipeline_with_description(self, pipeline_description: str) -> dict:
253
+ async def async_generate_pipeline_from_description(self, pipeline_description: str) -> dict:
246
254
  splited_block_descriptions = await self.__async_split_description_by_blocks(
247
255
  pipeline_description)
248
256
  blocks = {}
@@ -250,11 +258,17 @@ class LLMPipelineWizard:
250
258
  for line in splited_block_descriptions.strip().split('\n'):
251
259
  if line.startswith("BLOCK") and ":" in line:
252
260
  # Extract the block_id and block_description from the line
253
- raw_block_id, block_description = line.split(":", 1)
254
- block_id = raw_block_id.strip().split(" ")[-1]
255
- block_description = block_description.strip()
256
- block_tasks.append(
257
- self.__async_generate_blocks(blocks, block_id, block_description))
261
+ match = re.search(BLOCK_SPLIT_PATTERN, line)
262
+ if match:
263
+ block_id = match.group(1)
264
+ block_description = match.group(2).strip()
265
+ upstream_blocks = match.group(3).split(", ")
266
+ block_tasks.append(
267
+ self.__async_generate_blocks(
268
+ blocks,
269
+ block_id,
270
+ block_description,
271
+ upstream_blocks))
258
272
  await asyncio.gather(*block_tasks)
259
273
  return blocks
260
274
 
@@ -70,6 +70,7 @@ BlockPolicy.allow_write([
70
70
  'pipelines',
71
71
  'priority',
72
72
  'replicated_block',
73
+ 'require_unique_name',
73
74
  'type',
74
75
  'upstream_blocks',
75
76
  'uuid',
@@ -47,6 +47,7 @@ PipelineRunPolicy.allow_read(PipelineRunPresenter.default_attributes + [
47
47
  PipelineRunPolicy.allow_read(PipelineRunPresenter.default_attributes + [
48
48
  'block_runs',
49
49
  'block_runs_count',
50
+ 'completed_block_runs_count',
50
51
  'pipeline_schedule_name',
51
52
  'pipeline_schedule_token',
52
53
  'pipeline_schedule_type',
@@ -39,6 +39,7 @@ PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes +
39
39
 
40
40
  PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes + [
41
41
  'event_matchers',
42
+ 'tags',
42
43
  ], scopes=[
43
44
  OauthScope.CLIENT_PRIVATE,
44
45
  ], on_action=[
@@ -48,6 +49,7 @@ PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes +
48
49
  PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes + [
49
50
  'event_matchers',
50
51
  'runtime_average',
52
+ 'tags',
51
53
  ], scopes=[
52
54
  OauthScope.CLIENT_PRIVATE,
53
55
  ], on_action=[
@@ -58,6 +60,7 @@ PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes +
58
60
  'event_matchers',
59
61
  'last_pipeline_run_status',
60
62
  'pipeline_runs_count',
63
+ 'tags',
61
64
  ], scopes=[
62
65
  OauthScope.CLIENT_PRIVATE,
63
66
  ], on_action=[
@@ -89,6 +92,7 @@ PipelineSchedulePolicy.allow_write([
89
92
  'sla',
90
93
  'start_time',
91
94
  'status',
95
+ 'tags',
92
96
  'variables',
93
97
  ], scopes=[
94
98
  OauthScope.CLIENT_PRIVATE,
@@ -102,3 +106,11 @@ PipelineSchedulePolicy.allow_query([
102
106
  ], scopes=[
103
107
  OauthScope.CLIENT_PRIVATE,
104
108
  ], condition=lambda policy: policy.has_at_least_viewer_role())
109
+
110
+ PipelineSchedulePolicy.allow_query([
111
+ 'tag[]',
112
+ ], scopes=[
113
+ OauthScope.CLIENT_PRIVATE,
114
+ ], on_action=[
115
+ constants.LIST,
116
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
@@ -14,8 +14,26 @@ TagPolicy.allow_actions([
14
14
  OauthScope.CLIENT_PRIVATE,
15
15
  ], condition=lambda policy: policy.has_at_least_viewer_role())
16
16
 
17
+ TagPolicy.allow_actions([
18
+ constants.CREATE,
19
+ ], scopes=[
20
+ OauthScope.CLIENT_PRIVATE,
21
+ ], condition=lambda policy: policy.has_at_least_editor_role())
22
+
17
23
  TagPolicy.allow_read(TagPresenter.default_attributes + [], scopes=[
18
24
  OauthScope.CLIENT_PRIVATE,
19
25
  ], on_action=[
20
26
  constants.LIST,
21
27
  ], condition=lambda policy: policy.has_at_least_viewer_role())
28
+
29
+ TagPolicy.allow_read(TagPresenter.default_attributes + [], scopes=[
30
+ OauthScope.CLIENT_PRIVATE,
31
+ ], on_action=[
32
+ constants.CREATE,
33
+ ], condition=lambda policy: policy.has_at_least_editor_role())
34
+
35
+ TagPolicy.allow_write(TagPresenter.default_attributes + [], scopes=[
36
+ OauthScope.CLIENT_PRIVATE,
37
+ ], on_action=[
38
+ constants.CREATE,
39
+ ], condition=lambda policy: policy.has_at_least_editor_role())
@@ -17,4 +17,7 @@ class BlockRunPresenter(BasePresenter):
17
17
  ]
18
18
 
19
19
  def present(self, **kwargs):
20
- return self.model.to_dict()
20
+ if isinstance(self.model, dict):
21
+ return self.model
22
+ else:
23
+ return self.model.to_dict()
@@ -27,6 +27,7 @@ class PipelineRunPresenter(BasePresenter):
27
27
  additional_attributes = [
28
28
  'block_runs',
29
29
  'block_runs_count',
30
+ 'completed_block_runs_count',
30
31
  'pipeline_schedule_name',
31
32
  'pipeline_schedule_token',
32
33
  'pipeline_schedule_type',
@@ -66,6 +67,7 @@ PipelineRunPresenter.register_format(
66
67
  PipelineRunPresenter.default_attributes + [
67
68
  'block_runs',
68
69
  'block_runs_count',
70
+ 'completed_block_runs_count',
69
71
  'pipeline_schedule_name',
70
72
  'pipeline_schedule_token',
71
73
  'pipeline_schedule_type',
@@ -26,17 +26,24 @@ class PipelineSchedulePresenter(BasePresenter):
26
26
  data = self.model.to_dict()
27
27
 
28
28
  if constants.LIST == display_format:
29
- return self.model.to_dict(include_attributes=[
29
+ data = self.model.to_dict(include_attributes=[
30
30
  'event_matchers',
31
31
  'last_pipeline_run_status',
32
32
  'pipeline_runs_count',
33
33
  ])
34
+ data['tags'] = sorted([tag.name for tag in self.get_tag_associations])
35
+
36
+ return data
34
37
  elif display_format in [constants.DETAIL, constants.UPDATE]:
35
- return self.model.to_dict(include_attributes=[
38
+ data = self.model.to_dict(include_attributes=[
36
39
  'event_matchers',
37
40
  ])
41
+ data['tags'] = sorted([tag.name for tag in self.get_tag_associations])
42
+
43
+ return data
38
44
  elif 'with_runtime_average' == display_format:
39
45
  data['runtime_average'] = self.model.runtime_average()
46
+ data['tags'] = sorted([tag.name for tag in self.get_tag_associations])
40
47
 
41
48
  return data
42
49
 
@@ -3,5 +3,8 @@ from mage_ai.api.presenters.BasePresenter import BasePresenter
3
3
 
4
4
  class TagPresenter(BasePresenter):
5
5
  default_attributes = [
6
+ 'description',
7
+ 'id',
8
+ 'name',
6
9
  'uuid',
7
10
  ]
@@ -1,10 +1,13 @@
1
1
  from datetime import datetime
2
+
3
+ import pytz
4
+ from sqlalchemy import desc
5
+
2
6
  from mage_ai.api.resources.DatabaseResource import DatabaseResource
3
- from mage_ai.orchestration.backfills.service import start_backfill, cancel_backfill
7
+ from mage_ai.orchestration.backfills.service import cancel_backfill, start_backfill
4
8
  from mage_ai.orchestration.db import safe_db_query
5
9
  from mage_ai.orchestration.db.models.schedules import Backfill
6
10
  from mage_ai.shared.hash import extract, merge_dict
7
- from sqlalchemy import desc
8
11
 
9
12
  ALLOWED_PAYLOAD_KEYS = [
10
13
  'block_uuid',
@@ -51,7 +54,7 @@ class BackfillResource(DatabaseResource):
51
54
  if Backfill.Status.INITIAL == payload['status']:
52
55
  pipeline_runs += start_backfill(self.model)
53
56
  return super().update(dict(
54
- started_at=datetime.now(),
57
+ started_at=datetime.now(tz=pytz.UTC),
55
58
  status=payload['status'],
56
59
  ))
57
60
  elif Backfill.Status.CANCELLED == payload['status']:
@@ -36,6 +36,7 @@ class BlockResource(GenericResource):
36
36
  language = payload.get('language')
37
37
  name = payload.get('name')
38
38
  block_name = name or payload.get('uuid')
39
+ require_unique_name = payload.get('require_unique_name')
39
40
 
40
41
  payload_config = payload.get('config') or {}
41
42
 
@@ -120,6 +121,7 @@ class BlockResource(GenericResource):
120
121
  block_name,
121
122
  block_type,
122
123
  get_repo_path(),
124
+ require_unique_name=require_unique_name,
123
125
  **block_attributes,
124
126
  )
125
127
 
@@ -1,7 +1,12 @@
1
+ from sqlalchemy.orm import aliased
2
+
1
3
  from mage_ai.api.resources.DatabaseResource import DatabaseResource
2
- from mage_ai.orchestration.db.models.schedules import BlockRun, PipelineRun, PipelineSchedule
3
4
  from mage_ai.orchestration.db import safe_db_query
4
- from sqlalchemy.orm import aliased
5
+ from mage_ai.orchestration.db.models.schedules import (
6
+ BlockRun,
7
+ PipelineRun,
8
+ PipelineSchedule,
9
+ )
5
10
 
6
11
 
7
12
  class BlockRunResource(DatabaseResource):
@@ -24,16 +29,17 @@ class BlockRunResource(DatabaseResource):
24
29
  pipeline_schedule_name,
25
30
  ) = tup
26
31
 
27
- block_run = BlockRun()
28
- block_run.block_uuid = block_uuid
29
- block_run.completed_at = completed_at
30
- block_run.created_at = created_at
31
- block_run.id = id
32
- block_run.pipeline_run_id = pipeline_run_id
33
- block_run.status = status
34
- block_run.updated_at = updated_at
35
- block_run.pipeline_schedule_id = pipeline_schedule_id
36
- block_run.pipeline_schedule_name = pipeline_schedule_name
32
+ block_run = dict(
33
+ block_uuid=block_uuid,
34
+ completed_at=completed_at,
35
+ created_at=created_at,
36
+ id=id,
37
+ pipeline_run_id=pipeline_run_id,
38
+ status=status,
39
+ updated_at=updated_at,
40
+ pipeline_schedule_id=pipeline_schedule_id,
41
+ pipeline_schedule_name=pipeline_schedule_name,
42
+ )
37
43
 
38
44
  block_runs.append(block_run)
39
45
 
@@ -130,6 +130,29 @@ class DatabaseResource(BaseResource):
130
130
  def delete(self, **kwargs):
131
131
  return self.model.delete()
132
132
 
133
+ async def process_update(self, payload, **kwargs):
134
+ self.on_update_callback = None
135
+ self.on_update_failure_callback = None
136
+
137
+ try:
138
+ res = self.update(payload, **kwargs)
139
+ if res and inspect.isawaitable(res):
140
+ res = await res
141
+
142
+ db_connection.session.commit()
143
+
144
+ if self.on_update_callback:
145
+ self.on_update_callback(resource=res)
146
+
147
+ return res
148
+ except Exception as err:
149
+ db_connection.session.rollback()
150
+
151
+ if self.on_update_failure_callback:
152
+ self.on_update_failure_callback(resource=res)
153
+
154
+ raise err
155
+
133
156
  @safe_db_query
134
157
  def update(self, payload, **kwargs):
135
158
  for k, v in payload.items():
@@ -265,7 +265,14 @@ class GitBranchResource(GenericResource):
265
265
  untracked_files: List[str],
266
266
  limit: int = None
267
267
  ) -> Dict:
268
- arr = modified_files + staged_files + untracked_files
268
+ arr = []
269
+
270
+ if modified_files and isinstance(modified_files, list):
271
+ arr += modified_files
272
+ if staged_files and isinstance(staged_files, list):
273
+ arr += staged_files
274
+ if untracked_files and isinstance(untracked_files, list):
275
+ arr += untracked_files
269
276
 
270
277
  if limit:
271
278
  arr = arr[:limit]
@@ -35,9 +35,12 @@ class GlobalDataProductResource(GenericResource):
35
35
 
36
36
  def update(self, payload, **kwargs):
37
37
  uuid = payload.get('uuid')
38
- if self.model.uuid != uuid and GlobalDataProduct.get(uuid):
38
+ if self.model and self.model.uuid != uuid and GlobalDataProduct.get(uuid):
39
39
  error = ApiError.RESOURCE_INVALID.copy()
40
40
  error.update(dict(message=f'A global data product with UUID {uuid} already exists.'))
41
41
  raise ApiError(error)
42
42
 
43
- self.model.update(payload)
43
+ if self.model:
44
+ self.model.update(payload)
45
+ else:
46
+ self.model = self.create(payload, self.current_user, **kwargs).model
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ from typing import Dict, List
2
3
 
3
4
  from sqlalchemy import or_
4
5
  from sqlalchemy.orm import aliased
@@ -312,17 +313,28 @@ class PipelineResource(BaseResource):
312
313
  schedule.update(status=status)
313
314
 
314
315
  @safe_db_query
315
- def cancel_pipeline_runs(status, pipeline_uuid):
316
- pipeline_runs = (
317
- PipelineRun.
318
- query.
319
- filter(PipelineRun.pipeline_uuid == pipeline_uuid).
320
- filter(PipelineRun.status.in_([
321
- PipelineRun.PipelineRunStatus.INITIAL,
322
- PipelineRun.PipelineRunStatus.RUNNING,
323
- ]))
324
- )
325
- for pipeline_run in pipeline_runs:
316
+ def cancel_pipeline_runs(
317
+ pipeline_uuid: str = None,
318
+ pipeline_runs: List[Dict] = None,
319
+ ):
320
+ if pipeline_runs is not None:
321
+ pipeline_run_ids = [run.get('id') for run in pipeline_runs]
322
+ pipeline_runs_to_cancel = (
323
+ PipelineRun.
324
+ query.
325
+ filter(PipelineRun.id.in_(pipeline_run_ids))
326
+ )
327
+ else:
328
+ pipeline_runs_to_cancel = (
329
+ PipelineRun.
330
+ query.
331
+ filter(PipelineRun.pipeline_uuid == pipeline_uuid).
332
+ filter(PipelineRun.status.in_([
333
+ PipelineRun.PipelineRunStatus.INITIAL,
334
+ PipelineRun.PipelineRunStatus.RUNNING,
335
+ ]))
336
+ )
337
+ for pipeline_run in pipeline_runs_to_cancel:
326
338
  PipelineScheduler(pipeline_run).stop()
327
339
 
328
340
  def retry_pipeline_runs(pipeline_runs):
@@ -334,15 +346,19 @@ class PipelineResource(BaseResource):
334
346
 
335
347
  def _update_callback(resource):
336
348
  if status:
349
+ pipeline_runs = payload.get('pipeline_runs')
337
350
  if status in [
338
351
  ScheduleStatus.ACTIVE.value,
339
352
  ScheduleStatus.INACTIVE.value,
340
353
  ]:
341
354
  update_schedule_status(status, pipeline_uuid)
342
355
  elif status == PipelineRun.PipelineRunStatus.CANCELLED.value:
343
- cancel_pipeline_runs(status, pipeline_uuid)
344
- elif status == 'retry' and payload.get('pipeline_runs'):
345
- retry_pipeline_runs(payload.get('pipeline_runs'))
356
+ if pipeline_runs is None:
357
+ cancel_pipeline_runs(pipeline_uuid=pipeline_uuid)
358
+ else:
359
+ cancel_pipeline_runs(pipeline_runs=pipeline_runs)
360
+ elif status == 'retry' and pipeline_runs:
361
+ retry_pipeline_runs(pipeline_runs)
346
362
 
347
363
  self.on_update_callback = _update_callback
348
364