mage-ai 0.9.46__py3-none-any.whl → 0.9.47__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. mage_ai/api/operations/base.py +27 -5
  2. mage_ai/api/policies/GlobalHookPolicy.py +1 -1
  3. mage_ai/api/policies/IntegrationSourcePolicy.py +62 -0
  4. mage_ai/api/policies/OauthPolicy.py +6 -6
  5. mage_ai/api/presenters/GlobalHookPresenter.py +1 -1
  6. mage_ai/api/presenters/IntegrationSourcePresenter.py +9 -2
  7. mage_ai/api/presenters/PipelinePresenter.py +2 -0
  8. mage_ai/api/presenters/PipelineRunPresenter.py +8 -3
  9. mage_ai/api/presenters/PipelineSchedulePresenter.py +22 -1
  10. mage_ai/api/resources/BlockResource.py +5 -0
  11. mage_ai/api/resources/DataProviderResource.py +2 -0
  12. mage_ai/api/resources/IntegrationSourceResource.py +149 -2
  13. mage_ai/data_integrations/sources/constants.py +5 -0
  14. mage_ai/data_integrations/utils/scheduler.py +57 -2
  15. mage_ai/data_preparation/executors/block_executor.py +9 -1
  16. mage_ai/data_preparation/models/block/__init__.py +25 -12
  17. mage_ai/data_preparation/models/block/data_integration/constants.py +3 -0
  18. mage_ai/data_preparation/models/block/data_integration/utils.py +196 -37
  19. mage_ai/data_preparation/models/block/sql/utils/shared.py +18 -1
  20. mage_ai/data_preparation/models/block/utils.py +28 -13
  21. mage_ai/data_preparation/models/global_hooks/constants.py +50 -1
  22. mage_ai/data_preparation/models/global_hooks/models.py +148 -84
  23. mage_ai/data_preparation/models/global_hooks/predicates.py +316 -0
  24. mage_ai/data_preparation/models/pipeline.py +2 -0
  25. mage_ai/data_preparation/models/pipelines/integration_pipeline.py +0 -1
  26. mage_ai/data_preparation/preferences.py +29 -18
  27. mage_ai/data_preparation/repo_manager.py +12 -2
  28. mage_ai/data_preparation/sync/__init__.py +2 -0
  29. mage_ai/data_preparation/templates/constants.py +14 -0
  30. mage_ai/data_preparation/templates/data_exporters/chroma.py +24 -0
  31. mage_ai/data_preparation/templates/data_exporters/streaming/rabbitmq.yaml +7 -0
  32. mage_ai/data_preparation/templates/data_loaders/chroma.py +27 -0
  33. mage_ai/data_preparation/templates/repo/io_config.yaml +3 -0
  34. mage_ai/io/base.py +1 -0
  35. mage_ai/io/chroma.py +153 -0
  36. mage_ai/io/config.py +8 -0
  37. mage_ai/orchestration/db/models/schedules.py +98 -34
  38. mage_ai/orchestration/pipeline_scheduler.py +58 -19
  39. mage_ai/server/constants.py +1 -1
  40. mage_ai/server/frontend_dist/404.html +2 -2
  41. mage_ai/server/frontend_dist/_next/static/N3FS4bHv0jpYeeg672uYK/_buildManifest.js +1 -0
  42. mage_ai/server/frontend_dist/_next/static/chunks/{1749-9a6276b2918fdae1.js → 1749-bf512b4dabbab7fa.js} +1 -1
  43. mage_ai/server/frontend_dist/_next/static/chunks/{1952-ac7722e8b1ab88fe.js → 1952-57858e7445d24413.js} +1 -1
  44. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/2714-1e79e9f2e998b544.js → frontend_dist/_next/static/chunks/2714-68fef54789d7eaeb.js} +1 -1
  45. mage_ai/server/frontend_dist/_next/static/chunks/2717-92cdffd87b6f6e05.js +1 -0
  46. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3419-f8d518d024e7b5c8.js → frontend_dist/_next/static/chunks/3419-715ca383fa15a5ef.js} +1 -1
  47. mage_ai/server/frontend_dist/_next/static/chunks/3437-b4d6a037cf5781f8.js +1 -0
  48. mage_ai/server/frontend_dist/_next/static/chunks/3943-c9fb980f03df6450.js +1 -0
  49. mage_ai/server/frontend_dist/_next/static/chunks/4267-cb102e060a43d9bd.js +1 -0
  50. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4366-93e09e5a4a7e182c.js → frontend_dist/_next/static/chunks/4366-3e52497942acbafe.js} +1 -1
  51. mage_ai/server/frontend_dist/_next/static/chunks/{4783-1a21d9be47574bba.js → 4783-422429203610c318.js} +1 -1
  52. mage_ai/server/frontend_dist/_next/static/chunks/5810-e26a0768db1cfdba.js +1 -0
  53. mage_ai/server/frontend_dist/_next/static/chunks/{5896-14e5a23b1c6a0769.js → 5896-7b8e36634d7d94eb.js} +1 -1
  54. mage_ai/server/frontend_dist/_next/static/chunks/{6285-e9b45335bfb9ccaf.js → 6285-648f9a732e100b2f.js} +1 -1
  55. mage_ai/server/frontend_dist/_next/static/chunks/6798-b904395b0c18647b.js +1 -0
  56. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7022-070ec0144a4d029c.js → frontend_dist/_next/static/chunks/7022-e76cae3ba5ee5312.js} +1 -1
  57. mage_ai/server/frontend_dist/_next/static/chunks/722-900f786d24f91b2e.js +1 -0
  58. mage_ai/server/frontend_dist/_next/static/chunks/{7361-694e1e4fb9c97d68.js → 7361-6c5c9063b9f91700.js} +1 -1
  59. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/8146-92e7ccfed169ee9c.js → frontend_dist/_next/static/chunks/8146-27f0e31f309897a5.js} +1 -1
  60. mage_ai/server/frontend_dist/_next/static/chunks/845-9a73c65fe3fdc328.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/8487-8e1c09546dff4dbf.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/9264-cc44b07f248707b0.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/9618-4eb49cdbd1ba11d7.js +1 -0
  64. mage_ai/server/frontend_dist/_next/static/chunks/{976-18c98af60b76f1a7.js → 976-0a8c2c4d7acd957b.js} +1 -1
  65. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-78c4a077a2f279c2.js +1 -0
  66. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-b37d221eb5ddc248.js +1 -0
  67. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-7adc543fc490367a.js +1 -0
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks-51d366993f6dd449.js +1 -0
  69. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{files-449a022f2f0f2d94.js → files-fe6e73463a20d67c.js} +1 -1
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/{manage-f83deb790548693b.js → manage-d8a38b5d1f50e798.js} +1 -1
  71. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-9adc2974aada27ba.js +1 -0
  72. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-51b1311dff2a974e.js +1 -0
  73. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-2333e524d34b474a.js +1 -0
  74. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e051057d9fe94f23.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-6d1afeb4a84f50f7.js} +1 -1
  75. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1ff9bb8e22ca1e75.js +1 -0
  76. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-11363aa58d51f4e1.js +1 -0
  77. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-779c3ef0676a12ac.js +1 -0
  78. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-bbea9a088657404a.js +1 -0
  79. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3737f2b0afc2ede3.js +1 -0
  80. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-3c8f062913c66f3e.js +1 -0
  81. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-c1f4ed17d501ccca.js +1 -0
  82. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-8bdd858240d5dbf6.js +1 -0
  83. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-dd4fb405695f74bf.js +1 -0
  84. mage_ai/server/frontend_dist/block-layout.html +2 -2
  85. mage_ai/server/frontend_dist/compute.html +5 -5
  86. mage_ai/server/frontend_dist/files.html +5 -5
  87. mage_ai/server/frontend_dist/global-data-products/[...slug].html +5 -5
  88. mage_ai/server/frontend_dist/global-data-products.html +5 -5
  89. mage_ai/server/frontend_dist/global-hooks/[...slug].html +5 -5
  90. mage_ai/server/frontend_dist/global-hooks.html +5 -5
  91. mage_ai/server/frontend_dist/index.html +2 -2
  92. mage_ai/server/frontend_dist/manage/files.html +5 -5
  93. mage_ai/server/frontend_dist/manage/settings.html +5 -5
  94. mage_ai/server/frontend_dist/manage/users/[user].html +5 -5
  95. mage_ai/server/frontend_dist/manage/users/new.html +5 -5
  96. mage_ai/server/frontend_dist/manage/users.html +5 -5
  97. mage_ai/server/frontend_dist/manage.html +5 -5
  98. mage_ai/server/frontend_dist/oauth.html +4 -4
  99. mage_ai/server/frontend_dist/overview.html +5 -5
  100. mage_ai/server/frontend_dist/pipeline-runs.html +5 -5
  101. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +5 -5
  102. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +5 -5
  103. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +5 -5
  104. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  105. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +5 -5
  106. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +5 -5
  107. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
  108. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +5 -5
  109. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +5 -5
  110. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +5 -5
  111. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +5 -5
  112. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +5 -5
  113. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +5 -5
  114. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +5 -5
  115. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  116. mage_ai/server/frontend_dist/pipelines.html +5 -5
  117. mage_ai/server/frontend_dist/settings/account/profile.html +5 -5
  118. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +5 -5
  119. mage_ai/server/frontend_dist/settings/workspace/permissions.html +5 -5
  120. mage_ai/server/frontend_dist/settings/workspace/preferences.html +5 -5
  121. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +5 -5
  122. mage_ai/server/frontend_dist/settings/workspace/roles.html +5 -5
  123. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +5 -5
  124. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +5 -5
  125. mage_ai/server/frontend_dist/settings/workspace/users.html +5 -5
  126. mage_ai/server/frontend_dist/settings.html +2 -2
  127. mage_ai/server/frontend_dist/sign-in.html +20 -20
  128. mage_ai/server/frontend_dist/templates/[...slug].html +5 -5
  129. mage_ai/server/frontend_dist/templates.html +5 -5
  130. mage_ai/server/frontend_dist/terminal.html +5 -5
  131. mage_ai/server/frontend_dist/test.html +5 -5
  132. mage_ai/server/frontend_dist/triggers.html +5 -5
  133. mage_ai/server/frontend_dist/version-control.html +5 -5
  134. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  135. mage_ai/server/frontend_dist_base_path_template/_next/static/aoO6jYZLVlUGCCdY-wmy8/_buildManifest.js +1 -0
  136. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1749-9a6276b2918fdae1.js → 1749-bf512b4dabbab7fa.js} +1 -1
  137. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1952-ac7722e8b1ab88fe.js → 1952-57858e7445d24413.js} +1 -1
  138. mage_ai/server/{frontend_dist/_next/static/chunks/2714-1e79e9f2e998b544.js → frontend_dist_base_path_template/_next/static/chunks/2714-68fef54789d7eaeb.js} +1 -1
  139. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-92cdffd87b6f6e05.js +1 -0
  140. mage_ai/server/{frontend_dist/_next/static/chunks/3419-f8d518d024e7b5c8.js → frontend_dist_base_path_template/_next/static/chunks/3419-715ca383fa15a5ef.js} +1 -1
  141. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3437-b4d6a037cf5781f8.js +1 -0
  142. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3943-c9fb980f03df6450.js +1 -0
  143. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4267-cb102e060a43d9bd.js +1 -0
  144. mage_ai/server/{frontend_dist/_next/static/chunks/4366-93e09e5a4a7e182c.js → frontend_dist_base_path_template/_next/static/chunks/4366-3e52497942acbafe.js} +1 -1
  145. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{4783-1a21d9be47574bba.js → 4783-422429203610c318.js} +1 -1
  146. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5810-e26a0768db1cfdba.js +1 -0
  147. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{5896-14e5a23b1c6a0769.js → 5896-7b8e36634d7d94eb.js} +1 -1
  148. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{6285-e9b45335bfb9ccaf.js → 6285-648f9a732e100b2f.js} +1 -1
  149. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6798-b904395b0c18647b.js +1 -0
  150. mage_ai/server/{frontend_dist/_next/static/chunks/7022-070ec0144a4d029c.js → frontend_dist_base_path_template/_next/static/chunks/7022-e76cae3ba5ee5312.js} +1 -1
  151. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/722-900f786d24f91b2e.js +1 -0
  152. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7361-694e1e4fb9c97d68.js → 7361-6c5c9063b9f91700.js} +1 -1
  153. mage_ai/server/{frontend_dist/_next/static/chunks/8146-92e7ccfed169ee9c.js → frontend_dist_base_path_template/_next/static/chunks/8146-27f0e31f309897a5.js} +1 -1
  154. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/845-9a73c65fe3fdc328.js +1 -0
  155. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8487-8e1c09546dff4dbf.js +1 -0
  156. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-cc44b07f248707b0.js +1 -0
  157. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9618-4eb49cdbd1ba11d7.js +1 -0
  158. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{976-18c98af60b76f1a7.js → 976-0a8c2c4d7acd957b.js} +1 -1
  159. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-78c4a077a2f279c2.js +1 -0
  160. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-b37d221eb5ddc248.js +1 -0
  161. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-7adc543fc490367a.js +1 -0
  162. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks-51d366993f6dd449.js +1 -0
  163. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{files-449a022f2f0f2d94.js → files-fe6e73463a20d67c.js} +1 -1
  164. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{manage-f83deb790548693b.js → manage-d8a38b5d1f50e798.js} +1 -1
  165. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-9adc2974aada27ba.js +1 -0
  166. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-51b1311dff2a974e.js +1 -0
  167. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-2333e524d34b474a.js +1 -0
  168. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e051057d9fe94f23.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-6d1afeb4a84f50f7.js} +1 -1
  169. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1ff9bb8e22ca1e75.js +1 -0
  170. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-11363aa58d51f4e1.js +1 -0
  171. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-779c3ef0676a12ac.js +1 -0
  172. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-bbea9a088657404a.js +1 -0
  173. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3737f2b0afc2ede3.js +1 -0
  174. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-3c8f062913c66f3e.js +1 -0
  175. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-c1f4ed17d501ccca.js +1 -0
  176. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-8bdd858240d5dbf6.js +1 -0
  177. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-dd4fb405695f74bf.js +1 -0
  178. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/compute.html +5 -5
  180. mage_ai/server/frontend_dist_base_path_template/files.html +5 -5
  181. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +5 -5
  182. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +5 -5
  183. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +5 -5
  184. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +5 -5
  185. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/manage/files.html +5 -5
  187. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +5 -5
  188. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +5 -5
  189. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +5 -5
  190. mage_ai/server/frontend_dist_base_path_template/manage/users.html +5 -5
  191. mage_ai/server/frontend_dist_base_path_template/manage.html +5 -5
  192. mage_ai/server/frontend_dist_base_path_template/oauth.html +4 -4
  193. mage_ai/server/frontend_dist_base_path_template/overview.html +5 -5
  194. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +5 -5
  195. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +5 -5
  196. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +5 -5
  197. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +5 -5
  198. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  199. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +5 -5
  200. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +5 -5
  201. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
  202. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +5 -5
  203. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +5 -5
  204. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +5 -5
  205. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +5 -5
  206. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +5 -5
  207. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +5 -5
  208. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +5 -5
  209. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  210. mage_ai/server/frontend_dist_base_path_template/pipelines.html +5 -5
  211. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +5 -5
  212. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +5 -5
  213. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +5 -5
  214. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +5 -5
  215. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +5 -5
  216. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +5 -5
  217. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +5 -5
  218. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +5 -5
  219. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +5 -5
  220. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  221. mage_ai/server/frontend_dist_base_path_template/sign-in.html +23 -23
  222. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +5 -5
  223. mage_ai/server/frontend_dist_base_path_template/templates.html +5 -5
  224. mage_ai/server/frontend_dist_base_path_template/terminal.html +5 -5
  225. mage_ai/server/frontend_dist_base_path_template/test.html +5 -5
  226. mage_ai/server/frontend_dist_base_path_template/triggers.html +5 -5
  227. mage_ai/server/frontend_dist_base_path_template/version-control.html +5 -5
  228. mage_ai/server/server.py +9 -3
  229. mage_ai/services/k8s/job_manager.py +1 -0
  230. mage_ai/settings/repo.py +3 -0
  231. mage_ai/shared/files.py +47 -0
  232. mage_ai/shared/models.py +1 -0
  233. mage_ai/streaming/constants.py +1 -0
  234. mage_ai/streaming/sinks/postgres.py +2 -0
  235. mage_ai/streaming/sinks/rabbitmq.py +76 -0
  236. mage_ai/streaming/sinks/sink_factory.py +4 -0
  237. mage_ai/tests/api/operations/test_operations_with_hooks.py +136 -91
  238. mage_ai/tests/api/policies/test_oauth_policy.py +38 -0
  239. mage_ai/tests/data_preparation/models/global_hooks/test_global_hooks.py +33 -8
  240. mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +82 -38
  241. mage_ai/tests/data_preparation/models/global_hooks/test_predicates.py +803 -0
  242. mage_ai/tests/data_preparation/models/global_hooks/test_utils.py +6 -1
  243. mage_ai/tests/data_preparation/models/test_block.py +26 -0
  244. mage_ai/tests/data_preparation/models/test_pipeline.py +10 -0
  245. mage_ai/tests/factory.py +40 -2
  246. mage_ai/tests/orchestration/test_pipeline_scheduler.py +82 -1
  247. mage_ai/tests/services/k8s/test_job_manager.py +16 -0
  248. mage_ai/tests/shared/mixins.py +60 -23
  249. mage_ai/tests/streaming/sinks/test_rabbitmq.py +36 -0
  250. {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/METADATA +7 -4
  251. {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/RECORD +257 -243
  252. {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/WHEEL +1 -1
  253. mage_ai/server/frontend_dist/_next/static/9jB4XPuz6BzxBcG9VNao5/_buildManifest.js +0 -1
  254. mage_ai/server/frontend_dist/_next/static/chunks/3943-9e1105393a3be0de.js +0 -1
  255. mage_ai/server/frontend_dist/_next/static/chunks/4267-fd4d8049e83178de.js +0 -1
  256. mage_ai/server/frontend_dist/_next/static/chunks/5810-12eadc488265d55b.js +0 -1
  257. mage_ai/server/frontend_dist/_next/static/chunks/595-0d174b1f9fbfce4f.js +0 -1
  258. mage_ai/server/frontend_dist/_next/static/chunks/6333-bc1b433b428a9095.js +0 -1
  259. mage_ai/server/frontend_dist/_next/static/chunks/722-a1584445357a276c.js +0 -1
  260. mage_ai/server/frontend_dist/_next/static/chunks/8487-032ef9b17d20aad9.js +0 -1
  261. mage_ai/server/frontend_dist/_next/static/chunks/9264-1d4f0327d42fed91.js +0 -1
  262. mage_ai/server/frontend_dist/_next/static/chunks/9618-2c5045255ac5a6e7.js +0 -1
  263. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-ebef928183f9a3bb.js +0 -1
  264. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-0f2d4be6fdca86ca.js +0 -1
  265. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-77edfa32d000e88b.js +0 -1
  266. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks-e561ae38cf5592e8.js +0 -1
  267. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-10e9a2d19541caa2.js +0 -1
  268. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c8d3a5289ab93f88.js +0 -1
  269. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-ff7e9108502f5716.js +0 -1
  270. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-0691711636fa95c7.js +0 -1
  271. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-2914e326a5f1ffe0.js +0 -1
  272. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-3a7500e6e53084d3.js +0 -1
  273. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-c0e551d265a8d467.js +0 -1
  274. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-e47db5c3eaf683af.js +0 -1
  275. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-55ac955dfa9a5a8d.js +0 -1
  276. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-29c92a9bc54ae5cd.js +0 -1
  277. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-572d82d6eb7a5d43.js +0 -1
  278. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-2d26d80370a2e481.js +0 -1
  279. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3943-9e1105393a3be0de.js +0 -1
  280. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4267-fd4d8049e83178de.js +0 -1
  281. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5810-12eadc488265d55b.js +0 -1
  282. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/595-0d174b1f9fbfce4f.js +0 -1
  283. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-bc1b433b428a9095.js +0 -1
  284. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/722-a1584445357a276c.js +0 -1
  285. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8487-032ef9b17d20aad9.js +0 -1
  286. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-1d4f0327d42fed91.js +0 -1
  287. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9618-2c5045255ac5a6e7.js +0 -1
  288. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-ebef928183f9a3bb.js +0 -1
  289. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-0f2d4be6fdca86ca.js +0 -1
  290. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-77edfa32d000e88b.js +0 -1
  291. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks-e561ae38cf5592e8.js +0 -1
  292. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-10e9a2d19541caa2.js +0 -1
  293. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c8d3a5289ab93f88.js +0 -1
  294. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-ff7e9108502f5716.js +0 -1
  295. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-0691711636fa95c7.js +0 -1
  296. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-2914e326a5f1ffe0.js +0 -1
  297. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-3a7500e6e53084d3.js +0 -1
  298. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-c0e551d265a8d467.js +0 -1
  299. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-e47db5c3eaf683af.js +0 -1
  300. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-55ac955dfa9a5a8d.js +0 -1
  301. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-29c92a9bc54ae5cd.js +0 -1
  302. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-572d82d6eb7a5d43.js +0 -1
  303. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-2d26d80370a2e481.js +0 -1
  304. mage_ai/server/frontend_dist_base_path_template/_next/static/uPDjJYpJMst1q6psbRyte/_buildManifest.js +0 -1
  305. /mage_ai/server/frontend_dist/_next/static/{9jB4XPuz6BzxBcG9VNao5 → N3FS4bHv0jpYeeg672uYK}/_ssgManifest.js +0 -0
  306. /mage_ai/server/frontend_dist_base_path_template/_next/static/{uPDjJYpJMst1q6psbRyte → aoO6jYZLVlUGCCdY-wmy8}/_ssgManifest.js +0 -0
  307. {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/LICENSE +0 -0
  308. {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/entry_points.txt +0 -0
  309. {mage_ai-0.9.46.dist-info → mage_ai-0.9.47.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,316 @@
1
+ import json
2
+ from abc import abstractmethod
3
+ from collections.abc import Iterable
4
+ from dataclasses import dataclass
5
+ from enum import Enum
6
+ from typing import Dict, List, Union
7
+
8
+ from mage_ai.api.resources.BaseResource import BaseResource
9
+ from mage_ai.data_preparation.models.block import Block
10
+ from mage_ai.data_preparation.models.global_hooks.constants import (
11
+ INTERNAL_DEFAULT_PREDICATE_VALUE,
12
+ PredicateAndOrOperator,
13
+ PredicateObjectType,
14
+ PredicateOperator,
15
+ PredicateValueDataType,
16
+ )
17
+ from mage_ai.data_preparation.models.pipeline import Pipeline
18
+ from mage_ai.shared.models import BaseDataClass
19
+
20
+
21
+ @dataclass
22
+ class PredicateValueType(BaseDataClass):
23
+ value_data_type: PredicateValueDataType = None
24
+ value_type: Dict = None
25
+
26
+ def __post_init__(self):
27
+ self.serialize_attribute_enum('value_data_type', PredicateValueDataType)
28
+
29
+ if self.value_type and isinstance(self.value_type, dict):
30
+ self.value_type = self.__class__.load(**self.value_type)
31
+
32
+ def to_dict(self, **kwargs) -> Dict:
33
+ data = super().to_dict(**kwargs)
34
+
35
+ if self.value_type and issubclass(self.value_type.__class__, BaseDataClass):
36
+ data['value_type'] = self.value_type.to_dict(**kwargs)
37
+
38
+ return data
39
+
40
+
41
+ @dataclass
42
+ class BasePredicate(BaseDataClass):
43
+ and_or_operator: PredicateAndOrOperator = None
44
+ left_object_keys: List[str] = None
45
+ left_object_type: PredicateObjectType = None
46
+ left_value: Union[bool, Dict, float, int, List, str] = None
47
+ left_value_type: PredicateValueType = None
48
+ operator: PredicateOperator = None
49
+ predicates: List = None
50
+ right_object_keys: List[str] = None
51
+ right_object_type: PredicateObjectType = None
52
+ right_value: Union[bool, Dict, float, int, List, str] = None
53
+ right_value_type: PredicateValueType = None
54
+
55
+ @abstractmethod
56
+ def validate(
57
+ self,
58
+ operation_resource: Union[BaseResource, Block, Dict, List[BaseResource], Pipeline],
59
+ error: Dict = None, # code, errors, message, type
60
+ hook: Dict = None,
61
+ meta: Dict = None,
62
+ metadata: Dict = None,
63
+ payload: Dict = None,
64
+ query: Dict = None,
65
+ resource: Dict = None,
66
+ resource_id: Union[int, str] = None,
67
+ resource_parent_id: Union[int, str] = None,
68
+ resources: Dict = None,
69
+ user: Dict = None,
70
+ ) -> bool:
71
+ return False
72
+
73
+
74
+ @dataclass
75
+ class HookPredicate(BasePredicate):
76
+ predicates: List[BasePredicate] = None
77
+
78
+ def __post_init__(self):
79
+ self.serialize_attribute_classes('predicates', self.__class__)
80
+ self.serialize_attribute_class('left_value_type', PredicateValueType)
81
+ self.serialize_attribute_class('right_value_type', PredicateValueType)
82
+ self.serialize_attribute_enum('and_or_operator', PredicateAndOrOperator)
83
+ self.serialize_attribute_enum('left_object_type', PredicateObjectType)
84
+ self.serialize_attribute_enum('operator', PredicateOperator)
85
+ self.serialize_attribute_enum('right_object_type', PredicateObjectType)
86
+
87
+ def validate(
88
+ self,
89
+ operation_resource: Union[BaseResource, Block, Dict, List[BaseResource], Pipeline],
90
+ **kwargs,
91
+ ) -> bool:
92
+ if self.predicates:
93
+ operator_func = all
94
+
95
+ if PredicateAndOrOperator.OR == self.and_or_operator:
96
+ operator_func = any
97
+
98
+ return operator_func([predicate.validate(
99
+ operation_resource,
100
+ **kwargs,
101
+ ) for predicate in self.predicates])
102
+
103
+ return self.__validate_resource(operation_resource, **kwargs)
104
+
105
+ def __validate_resource(
106
+ self,
107
+ operation_resource: Union[BaseResource, Block, Dict, List[BaseResource], Pipeline],
108
+ **kwargs,
109
+ ) -> bool:
110
+ if isinstance(operation_resource, Iterable) and not isinstance(operation_resource, dict):
111
+ return all([self.__validate(
112
+ operation_resource=res,
113
+ **kwargs,
114
+ ) for res in operation_resource])
115
+
116
+ return self.__validate(operation_resource=operation_resource, **kwargs)
117
+
118
+ def __validate(self, **kwargs) -> bool:
119
+
120
+ left_object = None
121
+ right_object = None
122
+
123
+ left_value_to_compare = INTERNAL_DEFAULT_PREDICATE_VALUE
124
+ right_value_to_compare = INTERNAL_DEFAULT_PREDICATE_VALUE
125
+
126
+ # Get the value from the object
127
+ if self.left_object_type:
128
+ key = self.left_object_type.value
129
+ if key in kwargs:
130
+ left_object = kwargs[key]
131
+
132
+ if self.right_object_type:
133
+ key = self.right_object_type.value
134
+ if key in kwargs:
135
+ right_object = kwargs[key]
136
+
137
+ # Get value from object using keys if self.right_value is not None
138
+ if self.left_value is not None:
139
+ left_value_to_compare = self.left_value
140
+ elif left_object:
141
+ if self.left_object_keys:
142
+ left_value_to_compare = get_value(left_object, self.left_object_keys)
143
+ else:
144
+ left_value_to_compare = left_object
145
+
146
+ # Convert left value to the specified data type
147
+ if self.left_value_type and INTERNAL_DEFAULT_PREDICATE_VALUE != left_value_to_compare:
148
+ left_value_to_compare = convert_value(left_value_to_compare, self.left_value_type)
149
+
150
+ # Get value from object using keys if self.right_value is not None
151
+ if self.right_value is not None:
152
+ right_value_to_compare = self.right_value
153
+ elif right_object:
154
+ if self.right_object_keys:
155
+ right_value_to_compare = get_value(right_object, self.right_object_keys)
156
+ else:
157
+ right_value_to_compare = right_object
158
+
159
+ # Convert value to the specified data type
160
+ if self.right_value_type and INTERNAL_DEFAULT_PREDICATE_VALUE != right_value_to_compare:
161
+ right_value_to_compare = convert_value(right_value_to_compare, self.right_value_type)
162
+
163
+ if INTERNAL_DEFAULT_PREDICATE_VALUE == left_value_to_compare:
164
+ left_value_to_compare = None
165
+
166
+ if INTERNAL_DEFAULT_PREDICATE_VALUE == right_value_to_compare:
167
+ right_value_to_compare = None
168
+
169
+ if self.operator:
170
+ return compare_using_operator(
171
+ self.operator,
172
+ left_value_to_compare,
173
+ right_value_to_compare,
174
+ )
175
+
176
+ return False
177
+
178
+
179
+ def get_value(
180
+ object_arg: Union[BaseResource, Block, Dict, List[BaseResource], Pipeline, int, str],
181
+ keys: List[str] = None,
182
+ ) -> Union[bool, Dict, float, int, List, str]:
183
+ value_temp = None
184
+
185
+ if keys:
186
+ if not isinstance(object_arg, Iterable) and (
187
+ issubclass(object_arg.__class__, BaseResource) or
188
+ isinstance(object_arg, Block) or
189
+ isinstance(object_arg, Pipeline)
190
+ ):
191
+ for idx, key in enumerate(keys):
192
+ if idx == 0:
193
+ value_temp = getattr(object_arg, key)
194
+ else:
195
+ value_temp = get_value(value_temp, [key])
196
+ elif isinstance(object_arg, Iterable) and \
197
+ not isinstance(object_arg, dict) and \
198
+ not isinstance(object_arg, str):
199
+
200
+ for idx, key in enumerate(keys):
201
+ if idx == 0:
202
+ if isinstance(key, str) and hasattr(object_arg, key):
203
+ value_temp = getattr(object_arg, key)
204
+ elif isinstance(key, int) or isinstance(key, float):
205
+ index_inner = int(key)
206
+
207
+ if object_arg and index_inner < len(object_arg):
208
+ value_temp = object_arg[index_inner]
209
+ else:
210
+ value_temp = get_value(value_temp, [key])
211
+ elif isinstance(object_arg, dict):
212
+ for idx, key in enumerate(keys):
213
+ if idx == 0:
214
+ value_temp = object_arg.get(key)
215
+ else:
216
+ value_temp = get_value(value_temp, [key])
217
+
218
+ if callable(value_temp):
219
+ value_temp = value_temp()
220
+
221
+ return value_temp
222
+
223
+
224
+ def convert_value(
225
+ value: Union[bool, Dict, float, int, List, str],
226
+ value_type: PredicateValueType,
227
+ ) -> Union[bool, Dict, float, int, List, str]:
228
+ value_data_type = value_type.value_data_type
229
+ value_type_sub = value_type.value_type
230
+
231
+ if PredicateValueDataType.BOOLEAN == value_data_type:
232
+ value = bool(value)
233
+ elif PredicateValueDataType.DICTIONARY == value_data_type:
234
+ if value is not None:
235
+ if isinstance(value, str):
236
+ value = json.loads(value)
237
+ if value_type_sub:
238
+ for k, v in value.items():
239
+ value[k] = convert_value(v, value_type_sub)
240
+ elif PredicateValueDataType.FLOAT == value_data_type:
241
+ if value is not None:
242
+ value = float(value)
243
+ elif PredicateValueDataType.INTEGER == value_data_type:
244
+ if value is not None:
245
+ value = int(value)
246
+ elif PredicateValueDataType.LIST == value_data_type:
247
+ if value is not None:
248
+ if isinstance(value, str):
249
+ value = json.loads(value)
250
+ if value_type_sub:
251
+ value = [convert_value(v, value_type_sub) for v in value]
252
+ elif PredicateValueDataType.STRING == value_data_type:
253
+ if value is None:
254
+ value = ''
255
+ if isinstance(value, Enum):
256
+ value = value.value
257
+ value = str(value)
258
+
259
+ return value
260
+
261
+
262
+ def compare_using_operator(
263
+ operator: PredicateOperator,
264
+ left_value: Union[bool, Dict, float, int, List, str],
265
+ right_value: Union[bool, Dict, float, int, List, str],
266
+ ) -> bool:
267
+ try:
268
+ if operator in [
269
+ PredicateOperator.GREATER_THAN,
270
+ PredicateOperator.GREATER_THAN_OR_EQUALS,
271
+ PredicateOperator.LESS_THAN,
272
+ PredicateOperator.LESS_THAN_OR_EQUALS,
273
+ ]:
274
+ if (
275
+ left_value is not None and
276
+ not isinstance(left_value, str) and
277
+ (isinstance(left_value, dict) or isinstance(left_value, Iterable))
278
+ ) or (
279
+ right_value is not None and
280
+ not isinstance(right_value, str) and
281
+ (isinstance(right_value, dict) or isinstance(right_value, Iterable))
282
+ ):
283
+ if left_value is None:
284
+ left_value = 0
285
+ else:
286
+ left_value = len(left_value)
287
+
288
+ if right_value is None:
289
+ right_value = 0
290
+ else:
291
+ right_value = len(right_value)
292
+
293
+ if PredicateOperator.EQUALS == operator:
294
+ return left_value == right_value
295
+ if PredicateOperator.GREATER_THAN == operator:
296
+ return left_value > right_value
297
+ if PredicateOperator.GREATER_THAN_OR_EQUALS == operator:
298
+ return left_value >= right_value
299
+ if PredicateOperator.INCLUDES == operator:
300
+ return left_value in right_value
301
+ if PredicateOperator.LESS_THAN == operator:
302
+ return left_value < right_value
303
+ if PredicateOperator.LESS_THAN_OR_EQUALS == operator:
304
+ return left_value <= right_value
305
+ if PredicateOperator.NOT_EQUALS == operator:
306
+ return left_value != right_value
307
+ if PredicateOperator.NOT_INCLUDES == operator:
308
+ return left_value not in right_value
309
+ if PredicateOperator.NOT_PRESENT == operator:
310
+ return False if left_value else True
311
+ if PredicateOperator.PRESENT == operator:
312
+ return True if left_value else False
313
+ except TypeError as err:
314
+ print(f'[ERROR] Predicate error comparing {left_value} {operator} {right_value}: {err}.')
315
+
316
+ return False
@@ -643,6 +643,7 @@ class Pipeline:
643
643
  executor_type=self.executor_type,
644
644
  name=self.name,
645
645
  notification_config=self.notification_config,
646
+ remote_variables_dir=self.remote_variables_dir,
646
647
  retry_config=self.retry_config,
647
648
  run_pipeline_in_one_process=self.run_pipeline_in_one_process,
648
649
  settings=self.settings.to_dict() if self.settings else self.settings,
@@ -650,6 +651,7 @@ class Pipeline:
650
651
  type=self.type.value if type(self.type) is not str else self.type,
651
652
  updated_at=updated_at,
652
653
  uuid=self.uuid,
654
+ variables_dir=self.variables_dir,
653
655
  )
654
656
 
655
657
  if self.variables is not None:
@@ -272,7 +272,6 @@ class IntegrationPipeline(Pipeline):
272
272
  sample_data_json = data.get('sample_data')
273
273
  sample_data = pd.DataFrame.from_dict(json.loads(sample_data_json))
274
274
  stream_id = data.get('stream_id')
275
-
276
275
  variables = {
277
276
  f'output_sample_data_{stream_id}': sample_data,
278
277
  }
@@ -20,6 +20,7 @@ GIT_SYNC_ON_PIPELINE_RUN_VAR = 'GIT_SYNC_ON_PIPELINE_RUN'
20
20
  GIT_SYNC_ON_START_VAR = 'GIT_SYNC_ON_START'
21
21
  GIT_SYNC_ON_EXECUTOR_START_VAR = 'GIT_SYNC_ON_EXECUTOR_START'
22
22
  GIT_SYNC_SUBMODULES = 'GIT_SYNC_SUBMODULES'
23
+ GIT_ENABLE_GIT_INTEGRATION_VAR = 'GIT_ENABLE_GIT_INTEGRATION'
23
24
 
24
25
 
25
26
  class Preferences:
@@ -30,8 +31,7 @@ class Preferences:
30
31
  user: User = None,
31
32
  ):
32
33
  self.repo_path = repo_path or get_repo_path()
33
- self.preferences_file_path = \
34
- os.path.join(self.repo_path, PREFERENCES_FILE)
34
+ self.preferences_file_path = os.path.join(self.repo_path, PREFERENCES_FILE)
35
35
  self.user = user
36
36
  project_preferences = dict()
37
37
  try:
@@ -47,33 +47,43 @@ class Preferences:
47
47
  pass
48
48
 
49
49
  # Git settings
50
- env_sync_config = dict()
51
50
  if os.getenv(GIT_REPO_LINK_VAR):
52
- env_sync_config = dict(
51
+ self.sync_config = dict(
53
52
  remote_repo_link=os.getenv(GIT_REPO_LINK_VAR),
54
53
  repo_path=os.getenv(GIT_REPO_PATH_VAR, os.getcwd()),
55
54
  auth_type=os.getenv(GIT_AUTH_TYPE_VAR),
56
55
  username=os.getenv(GIT_USERNAME_VAR),
57
56
  email=os.getenv(GIT_EMAIL_VAR),
58
57
  branch=os.getenv(GIT_BRANCH_VAR),
59
- sync_on_pipeline_run=bool(int(os.getenv(GIT_SYNC_ON_PIPELINE_RUN_VAR) or 0)),
58
+ sync_on_pipeline_run=bool(
59
+ int(os.getenv(GIT_SYNC_ON_PIPELINE_RUN_VAR) or 0)
60
+ ),
60
61
  sync_on_start=bool(int(os.getenv(GIT_SYNC_ON_START_VAR) or 0)),
61
- sync_on_executor_start=bool(int(os.getenv(GIT_SYNC_ON_EXECUTOR_START_VAR) or 0)),
62
+ sync_on_executor_start=bool(
63
+ int(os.getenv(GIT_SYNC_ON_EXECUTOR_START_VAR) or 0)
64
+ ),
62
65
  sync_submodules=bool(int(os.getenv(GIT_SYNC_SUBMODULES) or 0)),
66
+ enable_git_integration=bool(
67
+ int(os.getenv(GIT_ENABLE_GIT_INTEGRATION_VAR) or 0)
68
+ ),
63
69
  )
64
- project_sync_config = project_preferences.get('sync_config', dict())
65
- if user:
66
- user_git_settings = user.git_settings or {}
67
- project_sync_config = merge_dict(project_sync_config, user_git_settings)
70
+ else:
71
+ project_sync_config = project_preferences.get('sync_config', dict())
72
+ if user:
73
+ user_git_settings = user.git_settings or {}
74
+ project_sync_config = merge_dict(project_sync_config, user_git_settings)
68
75
 
69
- self.sync_config = merge_dict(env_sync_config, project_sync_config)
76
+ self.sync_config = project_sync_config
70
77
 
71
78
  def is_git_integration_enabled(self) -> bool:
72
- return self.sync_config.get('remote_repo_link') and \
73
- self.sync_config.get('repo_path') and \
74
- self.sync_config.get('username') and \
75
- self.sync_config.get('email') and \
76
- self.sync_config.get('branch') is None
79
+ return (
80
+ self.sync_config.get('remote_repo_link')
81
+ and self.sync_config.get('repo_path')
82
+ and self.sync_config.get('username')
83
+ and self.sync_config.get('email')
84
+ and self.sync_config.get('branch') is None
85
+ or self.sync_config.get('enable_git_integration')
86
+ )
77
87
 
78
88
  def update_preferences(self, updates: Dict):
79
89
  preferences = self.to_dict()
@@ -90,8 +100,9 @@ class Preferences:
90
100
  def get_preferences(repo_path=None, user: User = None) -> Preferences:
91
101
  default_preferences = Preferences(repo_path=repo_path)
92
102
  if user:
93
- if user.preferences is None \
94
- and os.path.exists(default_preferences.preferences_file_path):
103
+ if user.preferences is None and os.path.exists(
104
+ default_preferences.preferences_file_path
105
+ ):
95
106
  return default_preferences
96
107
  else:
97
108
  return Preferences(user=user)
@@ -255,16 +255,26 @@ def get_repo_config(repo_path=None) -> RepoConfig:
255
255
 
256
256
 
257
257
  def get_project_type(repo_path=None) -> ProjectType:
258
+ from mage_ai.settings.repo import MAGE_PROJECT_TYPE_ENV_VAR
258
259
  try:
259
- return get_repo_config(repo_path=repo_path).project_type
260
+ project_type_from_env = os.getenv(MAGE_PROJECT_TYPE_ENV_VAR)
261
+ if project_type_from_env:
262
+ return ProjectType(project_type_from_env)
263
+ else:
264
+ return get_repo_config(repo_path=repo_path).project_type
260
265
  except Exception:
261
266
  # default to standalone project type
262
267
  return ProjectType.STANDALONE
263
268
 
264
269
 
265
270
  def get_cluster_type(repo_path=None) -> Optional[ClusterType]:
271
+ from mage_ai.settings.repo import MAGE_CLUSTER_TYPE_ENV_VAR
266
272
  try:
267
- return get_repo_config(repo_path=repo_path).cluster_type
273
+ cluster_type_from_env = os.getenv(MAGE_CLUSTER_TYPE_ENV_VAR)
274
+ if cluster_type_from_env:
275
+ return ClusterType(cluster_type_from_env)
276
+ else:
277
+ return get_repo_config(repo_path=repo_path).cluster_type
268
278
  except Exception:
269
279
  # default to None
270
280
  return None
@@ -32,6 +32,8 @@ class GitConfig(BaseConfig):
32
32
  ssh_private_key_secret_name: str = GIT_SSH_PRIVATE_KEY_SECRET_NAME
33
33
  ssh_public_key_secret_name: str = GIT_SSH_PUBLIC_KEY_SECRET_NAME
34
34
  access_token_secret_name: str = GIT_ACCESS_TOKEN_SECRET_NAME
35
+ # Force Mage to show git integration panel in the UI
36
+ enable_git_integration: bool = False
35
37
  # This is not necessary anymore, but leaving it for backwards compatibility
36
38
  type: str = 'git'
37
39
 
@@ -192,6 +192,13 @@ TEMPLATES_ONLY_FOR_V2 = [
192
192
  path='data_loaders/snowflake.py',
193
193
  ),
194
194
  # Databases
195
+ dict(
196
+ block_type=BlockType.DATA_LOADER,
197
+ groups=[GROUP_DATABASES],
198
+ language=BlockLanguage.PYTHON,
199
+ name='Chroma',
200
+ path='data_loaders/chroma.py',
201
+ ),
195
202
  dict(
196
203
  block_type=BlockType.DATA_LOADER,
197
204
  groups=[GROUP_DATABASES],
@@ -552,6 +559,13 @@ TEMPLATES_ONLY_FOR_V2 = [
552
559
  path='data_exporters/snowflake.py',
553
560
  ),
554
561
  # Databases
562
+ dict(
563
+ block_type=BlockType.DATA_EXPORTER,
564
+ groups=[GROUP_DATABASES],
565
+ language=BlockLanguage.PYTHON,
566
+ name='Chroma',
567
+ path='data_exporters/chroma.py',
568
+ ),
555
569
  dict(
556
570
  block_type=BlockType.DATA_EXPORTER,
557
571
  groups=[GROUP_DATABASES],
@@ -0,0 +1,24 @@
1
+ from os import path
2
+
3
+ from pandas import DataFrame
4
+
5
+ from mage_ai.settings.repo import get_repo_path
6
+ from mage_ai.io.config import ConfigFileLoader
7
+ from mage_ai.io.chroma import Chroma
8
+
9
+ if 'data_exporter' not in globals():
10
+ from mage_ai.data_preparation.decorators import data_exporter
11
+
12
+
13
+ @data_exporter
14
+ def export_data_to_chroma(df: DataFrame, **kwargs) -> None:
15
+ config_path = path.join(get_repo_path(), 'io_config.yaml')
16
+ config_profile = 'default'
17
+ document_column = 'documents'
18
+ new_collection = 'new_colletion'
19
+
20
+ Chroma.with_config(ConfigFileLoader(config_path, config_profile)).export(
21
+ df,
22
+ collection=new_collection,
23
+ document_column=document_column
24
+ )
@@ -0,0 +1,7 @@
1
+ connector_type: 'rabbitmq'
2
+ connection_host: 'localhost'
3
+ connection_port: 5672
4
+ queue_name: 'default'
5
+ username: 'guest'
6
+ password: 'guest'
7
+ amqp_url_virtual_host: '%2f'
@@ -0,0 +1,27 @@
1
+ {% extends "data_loaders/default.jinja" %}
2
+ {% block imports %}
3
+ from mage_ai.settings.repo import get_repo_path
4
+ from mage_ai.io.config import ConfigFileLoader
5
+ from mage_ai.io.chroma import Chroma
6
+ from os import path
7
+ {{ super() -}}
8
+ {% endblock %}
9
+
10
+
11
+ {% block content %}
12
+ @data_loader
13
+ def load_data_from_chroma(*args, **kwargs):
14
+ """
15
+ Template for loading data from Chroma.
16
+ """
17
+ query_embeddings = 'Query embeddings'
18
+ query_texts = 'Query texts'
19
+ n_results = 1
20
+ config_path = path.join(get_repo_path(), 'io_config.yaml')
21
+ config_profile = 'default'
22
+
23
+ return Chroma.with_config(ConfigFileLoader(config_path, config_profile)).load(
24
+ n_results=n_results,
25
+ query_embeddings=query_embeddings,
26
+ query_texts=query_texts)
27
+ {% endblock %}
@@ -12,6 +12,9 @@ default:
12
12
  AZURE_CLIENT_SECRET: "{{ env_var('AZURE_CLIENT_SECRET') }}"
13
13
  AZURE_STORAGE_ACCOUNT_NAME: "{{ env_var('AZURE_STORAGE_ACCOUNT_NAME') }}"
14
14
  AZURE_TENANT_ID: "{{ env_var('AZURE_TENANT_ID') }}"
15
+ # Chroma
16
+ CHROMA_COLLECTION: collection_name
17
+ CHROMA_PATH: path
15
18
  # Clickhouse
16
19
  CLICKHOUSE_DATABASE: default
17
20
  CLICKHOUSE_HOST: host.docker.internal
mage_ai/io/base.py CHANGED
@@ -16,6 +16,7 @@ QUERY_ROW_LIMIT = 10_000_000
16
16
  class DataSource(str, Enum):
17
17
  API = 'api'
18
18
  BIGQUERY = 'bigquery'
19
+ CHROMA = 'chroma'
19
20
  CLICKHOUSE = 'clickhouse'
20
21
  DRUID = 'druid'
21
22
  DUCKDB = 'duckdb'