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/server/server.py CHANGED
@@ -22,8 +22,9 @@ from mage_ai.data_preparation.preferences import get_preferences
22
22
  from mage_ai.data_preparation.repo_manager import (
23
23
  ProjectType,
24
24
  get_project_type,
25
+ get_variables_dir,
26
+ init_project_uuid,
25
27
  init_repo,
26
- update_project_uuid,
27
28
  )
28
29
  from mage_ai.data_preparation.shared.constants import MANAGE_ENV_VAR
29
30
  from mage_ai.data_preparation.sync import GitConfig
@@ -52,6 +53,7 @@ from mage_ai.server.constants import DATA_PREP_SERVER_PORT
52
53
  from mage_ai.server.docs_server import run_docs_server
53
54
  from mage_ai.server.kernel_output_parser import parse_output_message
54
55
  from mage_ai.server.kernels import DEFAULT_KERNEL_NAME
56
+ from mage_ai.server.logger import Logger
55
57
  from mage_ai.server.scheduler_manager import (
56
58
  SCHEDULER_AUTO_RESTART_INTERVAL,
57
59
  check_scheduler_status,
@@ -74,7 +76,7 @@ from mage_ai.settings import (
74
76
  SHELL_COMMAND,
75
77
  USE_UNIQUE_TERMINAL,
76
78
  )
77
- from mage_ai.settings.repo import set_repo_path
79
+ from mage_ai.settings.repo import DEFAULT_MAGE_DATA_DIR, get_repo_name, set_repo_path
78
80
  from mage_ai.shared.constants import InstanceType
79
81
  from mage_ai.shared.logger import LoggingLevel
80
82
  from mage_ai.shared.utils import is_port_in_use
@@ -85,9 +87,11 @@ BASE_PATH_EXPORTS_FOLDER = 'frontend_dist_base_path'
85
87
  BASE_PATH_TEMPLATE_EXPORTS_FOLDER = 'frontend_dist_base_path_template'
86
88
  BASE_PATH_PLACEHOLDER = 'CLOUD_NOTEBOOK_BASE_PATH_PLACEHOLDER_'
87
89
 
90
+ logger = Logger().new_server_logger(__name__)
91
+
88
92
 
89
93
  class MainPageHandler(tornado.web.RequestHandler):
90
- def get(self, *args):
94
+ def get(self, *args, **kwargs):
91
95
  self.render('index.html')
92
96
 
93
97
 
@@ -113,16 +117,26 @@ class ApiSchedulerHandler(BaseHandler):
113
117
  self.write(dict(scheduler=dict(status=scheduler_manager.get_status())))
114
118
 
115
119
 
116
- def replace_base_path(base_path: str) -> None:
120
+ def replace_base_path(base_path: str) -> str:
117
121
  """
118
- This function will create and go through the BASE_PATH_EXPORTS_FOLDER and replace all the
122
+ This function will create the BASE_PATH_EXPORTS_FOLDER and replace all the
119
123
  occurrences of CLOUD_NOTEBOOK_BASE_PATH_PLACEHOLDER_ with the base_path parameter.
120
124
 
121
125
  Args:
122
126
  base_path (str): The base path to replace the placeholder with.
127
+
128
+ Returns:
129
+ str: The path of the frontend static export folder with the replaced base paths.
123
130
  """
124
131
  src = os.path.join(os.path.dirname(__file__), BASE_PATH_TEMPLATE_EXPORTS_FOLDER)
125
- dst = os.path.join(os.path.dirname(__file__), BASE_PATH_EXPORTS_FOLDER)
132
+
133
+ directory = get_variables_dir()
134
+ # get_variables_dir can return an s3 path. In that case, use the DEFAULT_MAGE_DATA_DIR
135
+ # directory.
136
+ if directory.startswith('s3'):
137
+ directory = os.path.join(os.path.expanduser(DEFAULT_MAGE_DATA_DIR), get_repo_name())
138
+ os.makedirs(directory, exist_ok=True)
139
+ dst = os.path.join(directory, BASE_PATH_EXPORTS_FOLDER)
126
140
  if os.path.exists(dst):
127
141
  shutil.rmtree(dst)
128
142
  shutil.copytree(src, dst)
@@ -138,9 +152,10 @@ def replace_base_path(base_path: str) -> None:
138
152
  # replace favicon
139
153
  with open(filepath, 'w', encoding='utf-8') as f:
140
154
  f.write(s)
155
+ return dst
141
156
 
142
157
 
143
- def make_app(update_routes: bool = False):
158
+ def make_app(template_dir: str = None, update_routes: bool = False):
144
159
  shell_command = SHELL_COMMAND
145
160
  if shell_command is None:
146
161
  shell_command = 'bash'
@@ -151,7 +166,8 @@ def make_app(update_routes: bool = False):
151
166
  term_klass = MageUniqueTermManager
152
167
  term_manager = term_klass(shell_command=[shell_command])
153
168
 
154
- template_dir = BASE_PATH_EXPORTS_FOLDER if update_routes else EXPORTS_FOLDER
169
+ if template_dir is None:
170
+ template_dir = os.path.join(os.path.dirname(__file__), EXPORTS_FOLDER)
155
171
  routes = [
156
172
  (r'/', MainPageHandler),
157
173
  (r'/files', MainPageHandler),
@@ -171,22 +187,22 @@ def make_app(update_routes: bool = False):
171
187
  (
172
188
  r'/_next/static/(.*)',
173
189
  tornado.web.StaticFileHandler,
174
- {'path': os.path.join(os.path.dirname(__file__), f'{template_dir}/_next/static')},
190
+ {'path': os.path.join(template_dir, '_next/static')},
175
191
  ),
176
192
  (
177
193
  r'/fonts/(.*)',
178
194
  tornado.web.StaticFileHandler,
179
- {'path': os.path.join(os.path.dirname(__file__), f'{template_dir}/fonts')},
195
+ {'path': os.path.join(template_dir, 'fonts')},
180
196
  ),
181
197
  (
182
198
  r'/images/(.*)',
183
199
  tornado.web.StaticFileHandler,
184
- {'path': os.path.join(os.path.dirname(__file__), f'{template_dir}/images')},
200
+ {'path': os.path.join(template_dir, 'images')},
185
201
  ),
186
202
  (
187
203
  r'/(favicon.ico)',
188
204
  tornado.web.StaticFileHandler,
189
- {'path': os.path.join(os.path.dirname(__file__), template_dir)},
205
+ {'path': template_dir},
190
206
  ),
191
207
  (r'/websocket/', WebSocketServer),
192
208
  (r'/websocket/terminal', TerminalWebsocketServer, {'term_manager': term_manager}),
@@ -231,7 +247,9 @@ def make_app(update_routes: bool = False):
231
247
  (r'/api/(?P<resource>\w+)/(?P<pk>.+)', ApiResourceDetailHandler),
232
248
  (r'/files', MainPageHandler),
233
249
  (r'/global-data-products', MainPageHandler),
250
+ (r'/global-data-products/(?P<uuid>\w+)', MainPageHandler),
234
251
  (r'/templates', MainPageHandler),
252
+ (r'/templates/(?P<uuid>\w+)', MainPageHandler),
235
253
  (r'/version-control', MainPageHandler),
236
254
  ]
237
255
 
@@ -249,7 +267,7 @@ def make_app(update_routes: bool = False):
249
267
  return tornado.web.Application(
250
268
  updated_routes,
251
269
  autoreload=True,
252
- template_path=os.path.join(os.path.dirname(__file__), template_dir),
270
+ template_path=template_dir,
253
271
  )
254
272
 
255
273
 
@@ -262,15 +280,22 @@ async def main(
262
280
 
263
281
  # Update base path if environment variable is set
264
282
  update_routes = False
265
-
283
+ template_dir = None
266
284
  if BASE_PATH:
267
285
  try:
268
- replace_base_path(BASE_PATH)
286
+ template_dir = replace_base_path(BASE_PATH)
269
287
  update_routes = True
270
288
  except Exception:
271
- print('Failed to replace base path, using default routes.')
289
+ logger.warning(
290
+ 'Server failed to replace base path with error:\n%s',
291
+ traceback.format_exc(),
292
+ )
293
+ logger.warning('Continuing with default routes...')
272
294
 
273
- app = make_app(update_routes=update_routes)
295
+ app = make_app(
296
+ update_routes=update_routes,
297
+ template_dir=template_dir,
298
+ )
274
299
 
275
300
  port = int(port)
276
301
  max_port = port + 100
@@ -290,7 +315,7 @@ async def main(
290
315
  if update_routes:
291
316
  url = f'{url}/{BASE_PATH}'
292
317
  webbrowser.open_new_tab(url)
293
- print(f'Mage is running at {url} and serving project {project}')
318
+ logger.info(f'Mage is running at {url} and serving project {project}')
294
319
 
295
320
  db_connection.start_session(force=True)
296
321
 
@@ -302,18 +327,18 @@ async def main(
302
327
  try:
303
328
  sync = GitSync(sync_config)
304
329
  sync.sync_data()
305
- print(
330
+ logger.info(
306
331
  f'Successfully synced data from git repo: {sync_config.remote_repo_link}'
307
332
  f', branch: {sync_config.branch}'
308
333
  )
309
334
  except Exception as err:
310
- print(
335
+ logger.info(
311
336
  f'Failed to sync data from git repo: {sync_config.remote_repo_link}'
312
337
  f', branch: {sync_config.branch} with error: {str(err)}'
313
338
  )
314
339
 
315
340
  if REQUIRE_USER_AUTHENTICATION:
316
- print('User authentication is enabled.')
341
+ logger.info('User authentication is enabled.')
317
342
  # We need to sleep for a few seconds after creating all the tables or else there
318
343
  # may be an error trying to create users.
319
344
  sleep(5)
@@ -327,7 +352,7 @@ async def main(
327
352
  default_owner_role = Role.get_role(Role.DefaultRole.OWNER)
328
353
  owner_users = default_owner_role.users if default_owner_role else []
329
354
  if not legacy_owner_user and len(owner_users) == 0:
330
- print('User with owner permission doesn’t exist, creating owner user.')
355
+ logger.info('User with owner permission doesn’t exist, creating owner user.')
331
356
  if AUTHENTICATION_MODE.lower() == 'ldap':
332
357
  user = User.create(
333
358
  roles_new=[default_owner_role],
@@ -352,7 +377,8 @@ async def main(
352
377
  Oauth2Application.client_id == OAUTH2_APPLICATION_CLIENT_ID,
353
378
  ).first()
354
379
  if not oauth_client:
355
- print('OAuth2 application doesn’t exist for frontend, creating OAuth2 application.')
380
+ logger.info(
381
+ 'OAuth2 application doesn’t exist for frontend, creating OAuth2 application.')
356
382
  oauth_client = Oauth2Application.create(
357
383
  client_id=OAUTH2_APPLICATION_CLIENT_ID,
358
384
  client_type=Oauth2Application.ClientType.PUBLIC,
@@ -360,13 +386,13 @@ async def main(
360
386
  user_id=owner_user.id,
361
387
  )
362
388
 
363
- print('Initializing block cache.')
389
+ logger.info('Initializing block cache.')
364
390
  await BlockCache.initialize_cache(replace=True)
365
391
 
366
- print('Initializing tag cache.')
392
+ logger.info('Initializing tag cache.')
367
393
  await TagCache.initialize_cache(replace=True)
368
394
 
369
- print('Initializing block action object cache.')
395
+ logger.info('Initializing block action object cache.')
370
396
  await BlockActionObjectCache.initialize_cache(replace=True)
371
397
 
372
398
  # Check scheduler status periodically
@@ -414,7 +440,7 @@ def start_server(
414
440
  project_uuid=project_uuid,
415
441
  )
416
442
  set_repo_path(project)
417
- update_project_uuid()
443
+ init_project_uuid()
418
444
 
419
445
  asyncio.run(UsageStatisticLogger().project_impression())
420
446
 
@@ -1,8 +1,63 @@
1
1
  from mage_ai.services.spark.config import SparkConfig
2
+ from typing import List
2
3
  import os
3
4
 
4
5
 
6
+ def get_file_names(jars: List) -> List:
7
+ """
8
+ Extracts file names from a list of jar files.
9
+
10
+ Args:
11
+ jars (List): A list of jar files.
12
+
13
+ Returns:
14
+ List: A list of file names.
15
+ """
16
+ if jars is None:
17
+ return None
18
+
19
+ return [os.path.basename(jar) for jar in jars]
20
+
21
+
22
+ def contains_same_jars(jars_1: List, jars_2: List) -> bool:
23
+ """
24
+ Checks if two lists of jar files contain the same jars.
25
+ The order of the jars in the list does not matter.
26
+
27
+ Args:
28
+ jars_1 (List): A list of jar files.
29
+ jars_2 (List): A list of jar files.
30
+
31
+ Returns:
32
+ bool: True if the lists contain the same jars, False otherwise.
33
+ """
34
+ if jars_1 is None and jars_2 is None:
35
+ return True
36
+
37
+ if jars_1 is None or jars_2 is None:
38
+ return False
39
+
40
+ if len(jars_1) != len(jars_2):
41
+ return False
42
+
43
+ file_names_1 = get_file_names(jars_1)
44
+ file_names_2 = get_file_names(jars_2)
45
+
46
+ return set(file_names_1) == set(file_names_2)
47
+
48
+
5
49
  def has_same_spark_config(spark_session, spark_config: SparkConfig) -> bool:
50
+ """
51
+ Checks if the spark session has the same configuration as the spark config.
52
+
53
+ Args:
54
+ spark_session (SparkSession): The spark session.
55
+ spark_config (SparkConfig): The spark config.
56
+
57
+ Returns:
58
+ bool: True if the spark session has the same configuration as the
59
+ spark config, False otherwise.
60
+ """
6
61
  if spark_session is None:
7
62
  return False
8
63
 
@@ -24,8 +79,8 @@ def has_same_spark_config(spark_session, spark_config: SparkConfig) -> bool:
24
79
  if spark_session.conf.get(f'spark.executorEnv.{key}') != value:
25
80
  print(f'Different spark.executorEnv.{key} found!')
26
81
  return False
27
- if (spark_config.spark_jars and spark_config.spark_jars
28
- != spark_session.conf.get('spark.jars')):
82
+ if (spark_config.spark_jars and not contains_same_jars(
83
+ spark_config.spark_jars, spark_session.conf.get('spark.jars'))):
29
84
  print('Different spark.jars found!')
30
85
  return False
31
86
  if spark_config.others:
@@ -37,6 +92,24 @@ def has_same_spark_config(spark_session, spark_config: SparkConfig) -> bool:
37
92
 
38
93
 
39
94
  def get_spark_session(spark_config: SparkConfig):
95
+ """
96
+ Gets a Spark session.
97
+ If the given spark_config is None, then create a Spark session with the
98
+ default configuration.
99
+ If the given spark_config is not None, then check if the active Spark
100
+ session has the same configuration as the given spark_config.
101
+ If the active Spark session has the same configuration as the given
102
+ spark_config, then reuse the active Spark session.
103
+ If the active Spark session does not have the same configuration as the
104
+ given spark_config, then create a new Spark session with the given
105
+ spark_config.
106
+
107
+ Args:
108
+ spark_config (SparkConfig): The Spark configuration.
109
+
110
+ Returns:
111
+ SparkSession: The Spark session.
112
+ """
40
113
  from pyspark.conf import SparkConf
41
114
  from pyspark.sql import SparkSession
42
115
 
@@ -1,6 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
3
  DEFAULT_BATCH_SIZE = 100
4
+ DEFAULT_TIMEOUT_MS = 500
4
5
 
5
6
 
6
7
  class SourceType(str, Enum):
@@ -1,14 +1,16 @@
1
+ import importlib
2
+ import json
3
+ import time
1
4
  from dataclasses import dataclass
5
+ from enum import Enum
6
+ from typing import Callable, Dict
7
+
2
8
  from kafka import KafkaConsumer
9
+
3
10
  from mage_ai.shared.config import BaseConfig
4
- from mage_ai.streaming.constants import DEFAULT_BATCH_SIZE
11
+ from mage_ai.streaming.constants import DEFAULT_BATCH_SIZE, DEFAULT_TIMEOUT_MS
5
12
  from mage_ai.streaming.sources.base import BaseSource
6
- from mage_ai.streaming.sources.shared import SerializationMethod, SerDeConfig
7
- from enum import Enum
8
- from typing import Callable, Dict
9
- import importlib
10
- import json
11
- import time
13
+ from mage_ai.streaming.sources.shared import SerDeConfig, SerializationMethod
12
14
 
13
15
 
14
16
  class SecurityProtocol(str, Enum):
@@ -39,6 +41,7 @@ class KafkaConfig(BaseConfig):
39
41
  topic: str
40
42
  api_version: str = '0.10.2'
41
43
  batch_size: int = DEFAULT_BATCH_SIZE
44
+ timeout_ms: int = DEFAULT_TIMEOUT_MS
42
45
  security_protocol: SecurityProtocol = None
43
46
  ssl_config: SSLConfig = None
44
47
  sasl_config: SASLConfig = None
@@ -138,16 +141,21 @@ class KafkaSource(BaseSource):
138
141
  batch_size = self.config.batch_size
139
142
  else:
140
143
  batch_size = DEFAULT_BATCH_SIZE
144
+ if self.config.timeout_ms > 0:
145
+ timeout_ms = self.config.timeout_ms
146
+ else:
147
+ timeout_ms = DEFAULT_TIMEOUT_MS
148
+
141
149
  while True:
142
150
  # Response format is {TopicPartiton('topic1', 1): [msg1, msg2]}
143
151
  msg_pack = self.consumer.poll(
144
152
  max_records=batch_size,
145
- timeout_ms=500,
153
+ timeout_ms=timeout_ms,
146
154
  )
147
155
 
148
156
  message_values = []
149
157
  msg_printed = False
150
- for tp, messages in msg_pack.items():
158
+ for _tp, messages in msg_pack.items():
151
159
  for message in messages:
152
160
  if not msg_printed:
153
161
  self.__print_message(message)
@@ -0,0 +1,36 @@
1
+ from unittest.mock import patch
2
+
3
+
4
+ from mage_ai.data_preparation.models.custom_templates.custom_block_template import (
5
+ CustomBlockTemplate,
6
+ )
7
+ from mage_ai.data_preparation.models.custom_templates.utils import group_and_hydrate_files
8
+ from mage_ai.shared.array import find
9
+ from mage_ai.tests.base_test import DBTestCase
10
+
11
+
12
+ class CustomTemplatesUtilsTest(DBTestCase):
13
+ def test_group_and_hydrate_files(self):
14
+ file_dicts = [
15
+ None,
16
+ dict(parent_names=None),
17
+ dict(parent_names=[]),
18
+ dict(parent_names=[None]),
19
+ dict(parent_names=['mage']),
20
+ dict(parent_names=['mage', 'fire']),
21
+ ]
22
+
23
+ def load(template_uuid: str):
24
+ return CustomBlockTemplate(template_uuid=template_uuid)
25
+
26
+ with patch.object(
27
+ CustomBlockTemplate,
28
+ 'load',
29
+ load,
30
+ ):
31
+ arr = group_and_hydrate_files(file_dicts, CustomBlockTemplate)
32
+
33
+ self.assertTrue(find(lambda x: x.template_uuid == '', arr))
34
+ self.assertTrue(find(lambda x: x.template_uuid == 'None', arr))
35
+ self.assertTrue(find(lambda x: x.template_uuid == 'mage', arr))
36
+ self.assertTrue(find(lambda x: x.template_uuid == 'mage/fire', arr))
@@ -542,3 +542,51 @@ SELECT 1 AS id;
542
542
 
543
543
  block2 = pipeline.get_block('test_transformer')
544
544
  self.assertEqual([], block2.upstream_block_uuids)
545
+
546
+ def test_execute_block_from_notebook(self):
547
+ pipeline = Pipeline.create(
548
+ 'test_pipeline_execute_block_function_from_notebook',
549
+ repo_path=self.repo_path,
550
+ )
551
+ block = Block.create('test_data_loader', 'data_loader', self.repo_path, pipeline=pipeline)
552
+
553
+ with open(block.file_path, 'w') as file:
554
+ file.write("""import pandas as pd
555
+ if 'data_loader' not in globals():
556
+ from mage_ai.data_preparation.decorators import data_loader
557
+
558
+ @data_loader
559
+ def load_data():
560
+ data = {'col1': [1, 3], 'col2': [2, 4]}
561
+ df = pd.DataFrame(data)
562
+ return df
563
+ """)
564
+
565
+ output = block._execute_block(dict(), from_notebook=True)
566
+ self.assertIsNotNone(block.module)
567
+ self.assertEqual(len(output), 1)
568
+
569
+ def test_execute_block_from_notebook_no_decorator_definition(self):
570
+ pipeline = Pipeline.create(
571
+ 'test_pipeline_execute_block_function_from_notebook_no_decorator_definition',
572
+ repo_path=self.repo_path,
573
+ )
574
+ block = Block.create('test_data_loader', 'data_loader', self.repo_path, pipeline=pipeline)
575
+
576
+ with open(block.file_path, 'w') as file:
577
+ file.write("""import pandas as pd
578
+
579
+ @data_loader
580
+ def load_data():
581
+ data = {'col1': [1, 3], 'col2': [2, 4]}
582
+ df = pd.DataFrame(data)
583
+ return df
584
+
585
+ @test
586
+ def test_output(output, *args) -> None:
587
+ assert output is not None, 'The output is undefined'
588
+ """)
589
+
590
+ output = block._execute_block(dict(), from_notebook=True)
591
+ self.assertIsNotNone(block.module)
592
+ self.assertEqual(len(output), 1)
@@ -1,10 +1,15 @@
1
1
  import os
2
2
  import shutil
3
3
  import uuid
4
+ from unittest.mock import patch
4
5
 
5
6
  import yaml
6
7
 
7
- from mage_ai.data_preparation.repo_manager import RepoConfig
8
+ from mage_ai.data_preparation.repo_manager import (
9
+ RepoConfig,
10
+ get_project_uuid,
11
+ set_project_uuid_from_metadata,
12
+ )
8
13
  from mage_ai.settings.repo import MAGE_DATA_DIR_ENV_VAR
9
14
  from mage_ai.tests.base_test import DBTestCase
10
15
 
@@ -71,3 +76,16 @@ class RepoManagerTest(DBTestCase):
71
76
  )
72
77
  test_dir = os.path.expanduser(f'~/{dir_name}')
73
78
  shutil.rmtree(test_dir)
79
+
80
+ def test_set_project_uuid_from_metadata(self):
81
+ test_metadata_file = os.path.join(self.repo_path, 'test_repo_manager.yaml')
82
+ with open(test_metadata_file, 'w', encoding='utf-8') as f:
83
+ yaml.dump(dict(project_uuid='123456789'), f)
84
+
85
+ with patch(
86
+ 'mage_ai.data_preparation.repo_manager.get_metadata_path',
87
+ return_value=test_metadata_file
88
+ ):
89
+ set_project_uuid_from_metadata()
90
+ self.assertEqual(get_project_uuid(), '123456789')
91
+ os.remove(test_metadata_file)
@@ -52,7 +52,9 @@ class ServerTests(TestCase):
52
52
  self.assertIsNone(handler)
53
53
 
54
54
  @patch('mage_ai.server.server.BASE_PATH', 'random-test-string-1hasdfh')
55
- def test_replace_base_path(self):
55
+ @patch('mage_ai.server.server.get_variables_dir')
56
+ def test_replace_base_path(self, mock_variables_dir):
57
+ mock_variables_dir.return_value = os.path.dirname(server_module.__file__)
56
58
  with patch(
57
59
  'mage_ai.server.server.BASE_PATH_EXPORTS_FOLDER',
58
60
  'base_path_test',
@@ -66,7 +68,9 @@ class ServerTests(TestCase):
66
68
  shutil.rmtree(test_dir)
67
69
 
68
70
  @patch('mage_ai.server.server.BASE_PATH', 'test_prefix')
69
- def test_replace_base_path_directory_exists(self):
71
+ @patch('mage_ai.server.server.get_variables_dir')
72
+ def test_replace_base_path_directory_exists(self, mock_variables_dir):
73
+ mock_variables_dir.return_value = os.path.dirname(server_module.__file__)
70
74
  test_dir = os.path.join(os.path.dirname(server_module.__file__), 'base_path_test')
71
75
  os.makedirs(test_dir)
72
76
  with patch(
@@ -77,3 +81,17 @@ class ServerTests(TestCase):
77
81
 
78
82
  self.assertTrue(len(os.listdir(test_dir)) > 0)
79
83
  shutil.rmtree(test_dir)
84
+
85
+ @patch('mage_ai.server.server.BASE_PATH', 'test_prefix')
86
+ @patch('mage_ai.server.server.get_variables_dir')
87
+ def test_replace_base_path_s3_directory(self, mock_variables_dir):
88
+ mock_variables_dir.return_value = 's3://test-bucket/test-prefix'
89
+ test_dir = os.path.join(self.repo_path, 'base_path_test')
90
+ with patch(
91
+ 'mage_ai.server.server.DEFAULT_MAGE_DATA_DIR',
92
+ test_dir,
93
+ ):
94
+ replace_base_path(base_path='test_prefix')
95
+
96
+ self.assertTrue(len(os.listdir(os.path.join(test_dir, 'test'))) > 0)
97
+ shutil.rmtree(test_dir)
File without changes
@@ -0,0 +1,52 @@
1
+ from mage_ai.services.spark.spark import contains_same_jars, get_file_names
2
+ from mage_ai.tests.base_test import TestCase
3
+
4
+
5
+ class SparkTests(TestCase):
6
+ def test_get_file_names(self):
7
+ self.assertEqual(
8
+ get_file_names(['/home/spark-jars/aws-java-sdk-core-1.11.1026.jar']),
9
+ ['aws-java-sdk-core-1.11.1026.jar']
10
+ )
11
+ self.assertEqual(
12
+ get_file_names(['spark://************:2222/jars/aws-java-sdk-core-1.11.1026.jar']),
13
+ ['aws-java-sdk-core-1.11.1026.jar']
14
+ )
15
+ self.assertEqual(
16
+ get_file_names(['/home/spark-jars/test1.jar', '/home/spark-jars/test2.jar']),
17
+ ['test1.jar', 'test2.jar']
18
+ )
19
+ self.assertEqual(
20
+ get_file_names([
21
+ 'spark://************:2222/jars/test1.jar',
22
+ 'spark://************:2222/jars/test2.jar']),
23
+ ['test1.jar', 'test2.jar']
24
+ )
25
+
26
+ def test_contains_same_jars(self):
27
+ self.assertTrue(
28
+ contains_same_jars(
29
+ ['/home/spark-jars/aws-java-sdk-core-1.11.1026.jar'],
30
+ ['aws-java-sdk-core-1.11.1026.jar'])
31
+ )
32
+ self.assertTrue(
33
+ contains_same_jars(
34
+ ['spark://************:2222/jars/aws-java-sdk-core-1.11.1026.jar'],
35
+ ['aws-java-sdk-core-1.11.1026.jar'])
36
+ )
37
+ self.assertTrue(
38
+ contains_same_jars(
39
+ ['/home/spark-jars/aws-java-sdk-core-1.11.1026.jar'],
40
+ ['spark://************:2222/jars/aws-java-sdk-core-1.11.1026.jar'])
41
+ )
42
+ self.assertTrue(
43
+ contains_same_jars(
44
+ ['/home/spark-jars/test1.jar', '/home/spark-jars/test2.jar'],
45
+ ['spark://************:2222/jars/test2.jar',
46
+ 'spark://************:2222/jars/test1.jar'])
47
+ )
48
+ self.assertFalse(
49
+ contains_same_jars(
50
+ ['/home/spark-jars/test1.jar', '/home/spark-jars/test2.jar'],
51
+ ['spark://************:2222/jars/test1.jar'])
52
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mage-ai
3
- Version: 0.9.12
3
+ Version: 0.9.14
4
4
  Summary: Mage is a tool for building and deploying data pipelines.
5
5
  Home-page: https://github.com/mage-ai/mage-ai
6
6
  Author: Mage