mage-ai 0.9.66__py3-none-any.whl → 0.9.68__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 (263) hide show
  1. mage_ai/api/monitors/BaseMonitor.py +1 -2
  2. mage_ai/api/policies/PipelinePolicy.py +2 -0
  3. mage_ai/api/resources/BlockLayoutItemResource.py +2 -2
  4. mage_ai/api/resources/BlockResource.py +4 -3
  5. mage_ai/api/resources/CacheItemResource.py +1 -1
  6. mage_ai/api/resources/GitBranchResource.py +3 -5
  7. mage_ai/api/resources/PageBlockLayoutResource.py +2 -2
  8. mage_ai/api/resources/PipelineResource.py +13 -0
  9. mage_ai/api/resources/PipelineRunResource.py +10 -1
  10. mage_ai/cache/tag.py +3 -0
  11. mage_ai/cluster_manager/manage.py +4 -1
  12. mage_ai/data_preparation/decorators.py +15 -0
  13. mage_ai/data_preparation/executors/k8s_block_executor.py +8 -1
  14. mage_ai/data_preparation/executors/k8s_pipeline_executor.py +12 -1
  15. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +22 -12
  16. mage_ai/data_preparation/git/api.py +3 -0
  17. mage_ai/data_preparation/git/clients/gitlab.py +3 -2
  18. mage_ai/data_preparation/logging/gcs_logger_manager.py +7 -4
  19. mage_ai/data_preparation/models/block/__init__.py +45 -86
  20. mage_ai/data_preparation/models/block/block_factory.py +77 -0
  21. mage_ai/data_preparation/models/block/dbt/block.py +5 -7
  22. mage_ai/data_preparation/models/block/global_data_product/__init__.py +9 -3
  23. mage_ai/data_preparation/models/block/integration/__init__.py +12 -8
  24. mage_ai/data_preparation/models/block/platform/mixins.py +1 -1
  25. mage_ai/data_preparation/models/pipeline.py +80 -13
  26. mage_ai/data_preparation/storage/gcs_storage.py +28 -3
  27. mage_ai/data_preparation/storage/local_storage.py +18 -3
  28. mage_ai/data_preparation/storage/s3_storage.py +7 -2
  29. mage_ai/data_preparation/templates/constants.py +7 -0
  30. mage_ai/data_preparation/templates/data_loaders/streaming/generic_python.py +23 -0
  31. mage_ai/data_preparation/templates/template.py +6 -2
  32. mage_ai/data_preparation/variable_manager.py +2 -1
  33. mage_ai/io/bigquery.py +2 -0
  34. mage_ai/io/export_utils.py +3 -0
  35. mage_ai/io/oracledb.py +152 -5
  36. mage_ai/io/sql.py +4 -0
  37. mage_ai/orchestration/db/__init__.py +2 -2
  38. mage_ai/orchestration/db/models/schedules.py +2 -2
  39. mage_ai/orchestration/job_manager.py +6 -1
  40. mage_ai/orchestration/notification/sender.py +8 -0
  41. mage_ai/orchestration/pipeline_scheduler_original.py +10 -1
  42. mage_ai/server/constants.py +1 -1
  43. mage_ai/server/frontend_dist/404.html +2 -2
  44. mage_ai/server/frontend_dist/_next/static/chunks/3548-961ff79ca70038c7.js +1 -0
  45. mage_ai/server/frontend_dist/_next/static/chunks/{4241-ccd0126f5750cc35.js → 4241-4499461184ba0d23.js} +1 -1
  46. mage_ai/server/frontend_dist/_next/static/chunks/5627-237a3de578538022.js +1 -0
  47. mage_ai/server/frontend_dist/_next/static/chunks/{7966-5c1786fb7e7a48f5.js → 7966-f07b2913f7326b50.js} +1 -1
  48. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-08790743315de36a.js +1 -0
  49. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-13760bb72d823b69.js +1 -0
  50. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
  51. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
  52. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
  53. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
  54. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-bd0aff5a5ed8888c.js +1 -0
  55. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
  56. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
  57. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-d1ee961387c58b7f.js +1 -0
  58. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
  59. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cb88fd075a357fcf.js +1 -0
  60. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-ceb06e1616ee9610.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-8ff16ef9566e911a.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-d7a8bc51bb7a1082.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-f59d34429fe022ee.js +1 -0
  64. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
  65. mage_ai/server/{frontend_dist_base_path_template/_next/static/wxqkF4diPqRxUfP6Ac6ai → frontend_dist/_next/static/i8pymuJDTVHdWjUP1QSh1}/_buildManifest.js +1 -1
  66. mage_ai/server/frontend_dist/block-layout.html +2 -2
  67. mage_ai/server/frontend_dist/compute.html +2 -2
  68. mage_ai/server/frontend_dist/files.html +2 -2
  69. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  70. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  71. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  72. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  73. mage_ai/server/frontend_dist/index.html +2 -2
  74. mage_ai/server/frontend_dist/manage/files.html +2 -2
  75. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  76. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  77. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  78. mage_ai/server/frontend_dist/manage/users.html +2 -2
  79. mage_ai/server/frontend_dist/manage.html +2 -2
  80. mage_ai/server/frontend_dist/oauth.html +3 -3
  81. mage_ai/server/frontend_dist/overview.html +2 -2
  82. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  83. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  84. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  85. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  86. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  87. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  88. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  89. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  90. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  91. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  92. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  93. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  94. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  95. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  96. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  97. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  98. mage_ai/server/frontend_dist/pipelines.html +2 -2
  99. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  100. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  101. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  102. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  103. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  104. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  105. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  106. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  107. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  108. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  109. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  110. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  111. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  112. mage_ai/server/frontend_dist/settings.html +2 -2
  113. mage_ai/server/frontend_dist/sign-in.html +5 -5
  114. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  115. mage_ai/server/frontend_dist/templates.html +2 -2
  116. mage_ai/server/frontend_dist/terminal.html +2 -2
  117. mage_ai/server/frontend_dist/test.html +2 -2
  118. mage_ai/server/frontend_dist/triggers.html +2 -2
  119. mage_ai/server/frontend_dist/version-control.html +2 -2
  120. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  121. mage_ai/server/{frontend_dist/_next/static/rtugsJoijF2SsCCB5_yKS → frontend_dist_base_path_template/_next/static/CKCvjsYCf2imD2X8zAOBf}/_buildManifest.js +1 -1
  122. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-961ff79ca70038c7.js +1 -0
  123. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{4241-ccd0126f5750cc35.js → 4241-4499461184ba0d23.js} +1 -1
  124. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5627-237a3de578538022.js +1 -0
  125. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7966-5c1786fb7e7a48f5.js → 7966-f07b2913f7326b50.js} +1 -1
  126. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-08790743315de36a.js +1 -0
  127. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-13760bb72d823b69.js +1 -0
  128. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
  129. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
  130. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
  131. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
  132. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-bd0aff5a5ed8888c.js +1 -0
  133. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
  134. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
  135. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-d1ee961387c58b7f.js +1 -0
  136. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
  137. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cb88fd075a357fcf.js +1 -0
  138. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-ceb06e1616ee9610.js +1 -0
  139. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-8ff16ef9566e911a.js +1 -0
  140. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-d7a8bc51bb7a1082.js +1 -0
  141. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-f59d34429fe022ee.js +1 -0
  142. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
  143. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  144. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  145. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  146. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  147. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  148. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  149. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  150. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  151. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  152. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  153. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  154. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  155. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  156. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  157. mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
  158. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  159. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  160. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  161. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  162. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  163. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  164. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  165. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  166. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  167. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  168. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  169. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  172. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  173. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  181. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  183. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  188. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
  191. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  192. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  193. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  194. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  195. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  196. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  197. mage_ai/services/aws/s3/s3.py +8 -2
  198. mage_ai/services/k8s/job_manager.py +8 -0
  199. mage_ai/services/slack/slack.py +10 -1
  200. mage_ai/services/spark/spark.py +9 -2
  201. mage_ai/settings/backends.py +8 -8
  202. mage_ai/settings/models/configuration_option.py +10 -9
  203. mage_ai/settings/server.py +6 -1
  204. mage_ai/shared/files.py +19 -1
  205. mage_ai/shared/logger.py +12 -6
  206. mage_ai/shared/path_fixer.py +3 -0
  207. mage_ai/streaming/sources/base.py +5 -0
  208. mage_ai/streaming/sources/base_python.py +30 -0
  209. mage_ai/streaming/sources/kafka.py +2 -1
  210. mage_ai/streaming/sources/mongodb.py +4 -0
  211. mage_ai/streaming/sources/source_factory.py +25 -0
  212. mage_ai/tests/data_preparation/models/block/dbt/test_block.py +2 -2
  213. mage_ai/tests/data_preparation/models/block/dbt/test_block_sql.py +1 -1
  214. mage_ai/tests/data_preparation/models/block/dbt/test_block_yaml.py +1 -1
  215. mage_ai/tests/data_preparation/models/test_block.py +41 -3
  216. mage_ai/tests/orchestration/test_pipeline_scheduler.py +2 -0
  217. mage_ai/tests/settings/models/test_configuration_option.py +2 -2
  218. {mage_ai-0.9.66.dist-info → mage_ai-0.9.68.dist-info}/METADATA +3 -3
  219. {mage_ai-0.9.66.dist-info → mage_ai-0.9.68.dist-info}/RECORD +225 -222
  220. mage_ai/server/frontend_dist/_next/static/chunks/181-e61915415a976861.js +0 -1
  221. mage_ai/server/frontend_dist/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
  222. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-913116aa749f7ca6.js +0 -1
  223. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
  224. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
  225. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
  226. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
  227. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
  228. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-d84556cefbe31a1a.js +0 -1
  229. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
  230. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
  231. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
  232. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
  233. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
  234. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
  235. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
  236. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
  237. mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js +0 -1
  238. mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
  239. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/181-e61915415a976861.js +0 -1
  240. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
  241. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-913116aa749f7ca6.js +0 -1
  242. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
  243. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
  244. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
  245. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
  246. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
  247. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-d84556cefbe31a1a.js +0 -1
  248. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
  249. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
  250. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
  251. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
  252. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
  253. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
  254. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
  255. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
  256. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js +0 -1
  257. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
  258. /mage_ai/server/frontend_dist/_next/static/{rtugsJoijF2SsCCB5_yKS → i8pymuJDTVHdWjUP1QSh1}/_ssgManifest.js +0 -0
  259. /mage_ai/server/frontend_dist_base_path_template/_next/static/{wxqkF4diPqRxUfP6Ac6ai → CKCvjsYCf2imD2X8zAOBf}/_ssgManifest.js +0 -0
  260. {mage_ai-0.9.66.dist-info → mage_ai-0.9.68.dist-info}/LICENSE +0 -0
  261. {mage_ai-0.9.66.dist-info → mage_ai-0.9.68.dist-info}/WHEEL +0 -0
  262. {mage_ai-0.9.66.dist-info → mage_ai-0.9.68.dist-info}/entry_points.txt +0 -0
  263. {mage_ai-0.9.66.dist-info → mage_ai-0.9.68.dist-info}/top_level.txt +0 -0
@@ -90,7 +90,7 @@ from mage_ai.data_preparation.templates.data_integrations.utils import get_templ
90
90
  from mage_ai.data_preparation.templates.template import load_template
91
91
  from mage_ai.server.kernel_output_parser import DataType
92
92
  from mage_ai.services.spark.config import SparkConfig
93
- from mage_ai.services.spark.spark import get_spark_session
93
+ from mage_ai.services.spark.spark import SPARK_ENABLED, get_spark_session
94
94
  from mage_ai.settings.platform.constants import project_platform_activated
95
95
  from mage_ai.settings.repo import get_repo_path
96
96
  from mage_ai.shared.array import unique_by
@@ -339,7 +339,6 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
339
339
  self.upstream_blocks = []
340
340
  self.downstream_blocks = []
341
341
  self.test_functions = []
342
- self.global_vars = {}
343
342
  self.template_runtime_configuration = {}
344
343
 
345
344
  self.dynamic_block_index = None
@@ -724,41 +723,6 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
724
723
  widget=widget,
725
724
  )
726
725
 
727
- @classmethod
728
- def block_class_from_type(self, block_type: str, language=None, pipeline=None) -> 'Block':
729
- from mage_ai.data_preparation.models.block.constants import BLOCK_TYPE_TO_CLASS
730
- from mage_ai.data_preparation.models.block.integration import (
731
- DestinationBlock,
732
- SourceBlock,
733
- TransformerBlock,
734
- )
735
- from mage_ai.data_preparation.models.block.r import RBlock
736
- from mage_ai.data_preparation.models.block.sql import SQLBlock
737
- from mage_ai.data_preparation.models.widget import Widget
738
-
739
- if BlockType.CHART == block_type:
740
- return Widget
741
- elif BlockType.DBT == block_type:
742
- from mage_ai.data_preparation.models.block.dbt import DBTBlock
743
-
744
- return DBTBlock
745
- elif pipeline and PipelineType.INTEGRATION == pipeline.type:
746
- if BlockType.CALLBACK == block_type:
747
- return CallbackBlock
748
- elif BlockType.CONDITIONAL == block_type:
749
- return ConditionalBlock
750
- elif BlockType.DATA_LOADER == block_type:
751
- return SourceBlock
752
- elif BlockType.DATA_EXPORTER == block_type:
753
- return DestinationBlock
754
- else:
755
- return TransformerBlock
756
- elif BlockLanguage.SQL == language:
757
- return SQLBlock
758
- elif BlockLanguage.R == language:
759
- return RBlock
760
- return BLOCK_TYPE_TO_CLASS.get(block_type)
761
-
762
726
  @classmethod
763
727
  def create(
764
728
  self,
@@ -778,6 +742,8 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
778
742
  widget: bool = False,
779
743
  downstream_block_uuids: List[str] = None,
780
744
  ) -> 'Block':
745
+ from mage_ai.data_preparation.models.block.block_factory import BlockFactory
746
+
781
747
  """
782
748
  1. Create a new folder for block_type if not exist
783
749
  2. Create a new python file with code template
@@ -871,7 +837,11 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
871
837
  language,
872
838
  )
873
839
 
874
- block = self.block_class_from_type(block_type, pipeline=pipeline)(
840
+ block = BlockFactory.block_class_from_type(
841
+ block_type,
842
+ language=language,
843
+ pipeline=pipeline,
844
+ )(
875
845
  name,
876
846
  uuid,
877
847
  block_type,
@@ -932,34 +902,6 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
932
902
  block_uuids[t.value].append(f.split('.')[0])
933
903
  return block_uuids
934
904
 
935
- @classmethod
936
- def get_block(
937
- self,
938
- name,
939
- uuid,
940
- block_type,
941
- configuration=None,
942
- content=None,
943
- language=None,
944
- pipeline=None,
945
- status=BlockStatus.NOT_EXECUTED,
946
- ) -> 'Block':
947
- block_class = self.block_class_from_type(
948
- block_type,
949
- language=language,
950
- pipeline=pipeline,
951
- ) or Block
952
- return block_class(
953
- name,
954
- uuid,
955
- block_type,
956
- configuration=configuration,
957
- content=content,
958
- language=language,
959
- pipeline=pipeline,
960
- status=status,
961
- )
962
-
963
905
  @classmethod
964
906
  def get_block_from_file_path(self, file_path: str) -> 'Block':
965
907
  parts = get_path_parts(file_path)
@@ -1198,7 +1140,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1198
1140
  f'Please run upstream blocks {upstream_block_uuids} '
1199
1141
  'before running the current block.'
1200
1142
  )
1201
- global_vars = self.__enrich_global_vars(
1143
+ global_vars = self.enrich_global_vars(
1202
1144
  global_vars,
1203
1145
  dynamic_block_index=dynamic_block_index,
1204
1146
  )
@@ -2204,6 +2146,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
2204
2146
  self.pipeline.uuid,
2205
2147
  block_uuid,
2206
2148
  partition=execution_partition,
2149
+ max_results=DATAFRAME_SAMPLE_COUNT_PREVIEW,
2207
2150
  )
2208
2151
 
2209
2152
  if not include_print_outputs:
@@ -2445,8 +2388,10 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2445
2388
  return Template(self.executor_type).render(**get_template_vars())
2446
2389
  return self.executor_type
2447
2390
 
2448
- def get_pipelines_from_cache(self) -> List[Dict]:
2449
- arr = BlockCache().get_pipelines(self)
2391
+ def get_pipelines_from_cache(self, block_cache: BlockCache = None) -> List[Dict]:
2392
+ if block_cache is None:
2393
+ block_cache = BlockCache()
2394
+ arr = block_cache.get_pipelines(self)
2450
2395
 
2451
2396
  return unique_by(
2452
2397
  arr,
@@ -2497,11 +2442,13 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2497
2442
  def to_dict(
2498
2443
  self,
2499
2444
  include_block_catalog: bool = False,
2445
+ include_block_pipelines: bool = False,
2500
2446
  include_callback_blocks: bool = False,
2501
2447
  include_content: bool = False,
2502
2448
  include_outputs: bool = False,
2503
2449
  include_outputs_spark: bool = False,
2504
2450
  sample_count: int = None,
2451
+ block_cache: BlockCache = None,
2505
2452
  check_if_file_exists: bool = False,
2506
2453
  **kwargs,
2507
2454
  ) -> Dict:
@@ -2515,6 +2462,9 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2515
2462
  if include_block_catalog and self.is_data_integration() and self.pipeline:
2516
2463
  data['catalog'] = self.get_catalog_from_file()
2517
2464
 
2465
+ if include_block_pipelines:
2466
+ data['pipelines'] = self.get_pipelines_from_cache(block_cache=block_cache)
2467
+
2518
2468
  if include_outputs:
2519
2469
  include_outputs_use = include_outputs
2520
2470
  if self.is_using_spark() and self.compute_management_enabled():
@@ -2551,6 +2501,7 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2551
2501
  include_outputs: bool = False,
2552
2502
  include_outputs_spark: bool = False,
2553
2503
  sample_count: int = None,
2504
+ block_cache: BlockCache = None,
2554
2505
  check_if_file_exists: bool = False,
2555
2506
  **kwargs,
2556
2507
  ) -> Dict:
@@ -2596,7 +2547,7 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
2596
2547
  data['tags'] = self.tags()
2597
2548
 
2598
2549
  if include_block_pipelines:
2599
- data['pipelines'] = self.get_pipelines_from_cache()
2550
+ data['pipelines'] = self.get_pipelines_from_cache(block_cache=block_cache)
2600
2551
 
2601
2552
  return data
2602
2553
 
@@ -3037,7 +2988,7 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
3037
2988
  variable_mapping = merge_dict(output_variables, consolidated_print_variables)
3038
2989
  return variable_mapping
3039
2990
 
3040
- def __enrich_global_vars(
2991
+ def enrich_global_vars(
3041
2992
  self,
3042
2993
  global_vars: Dict = None,
3043
2994
  dynamic_block_index: int = None,
@@ -3093,6 +3044,8 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
3093
3044
  return global_vars
3094
3045
 
3095
3046
  def get_spark_session(self):
3047
+ if not SPARK_ENABLED:
3048
+ return None
3096
3049
  if self.spark_init and (not self.pipeline or
3097
3050
  not self.pipeline.spark_config):
3098
3051
  return self.spark
@@ -3658,23 +3611,29 @@ class AddonBlock(Block):
3658
3611
  global_vars['dynamic_block_index'] = dynamic_block_index
3659
3612
 
3660
3613
  if parent_block:
3614
+ if parent_block.global_vars is None:
3615
+ global_vars_copy = global_vars.copy()
3616
+ parent_block.enrich_global_vars(
3617
+ global_vars=global_vars_copy,
3618
+ dynamic_block_index=dynamic_block_index,
3619
+ )
3620
+ global_vars = merge_dict(parent_block.global_vars, global_vars)
3661
3621
  global_vars['parent_block_uuid'] = parent_block.uuid
3662
3622
 
3663
- if parent_block and \
3664
- parent_block.pipeline and \
3665
- PipelineType.INTEGRATION == parent_block.pipeline.type:
3666
-
3667
- template_runtime_configuration = parent_block.template_runtime_configuration
3668
- index = template_runtime_configuration.get('index', None)
3669
- is_last_block_run = template_runtime_configuration.get('is_last_block_run', False)
3670
- selected_streams = template_runtime_configuration.get('selected_streams', [])
3671
- stream = selected_streams[0] if len(selected_streams) >= 1 else None
3672
- destination_table = template_runtime_configuration.get('destination_table', stream)
3673
-
3674
- global_vars['index'] = index
3675
- global_vars['is_last_block_run'] = is_last_block_run
3676
- global_vars['stream'] = stream
3677
- global_vars['destination_table'] = destination_table
3623
+ if parent_block.pipeline and \
3624
+ PipelineType.INTEGRATION == parent_block.pipeline.type:
3625
+
3626
+ template_runtime_configuration = parent_block.template_runtime_configuration
3627
+ index = template_runtime_configuration.get('index', None)
3628
+ is_last_block_run = template_runtime_configuration.get('is_last_block_run', False)
3629
+ selected_streams = template_runtime_configuration.get('selected_streams', [])
3630
+ stream = selected_streams[0] if len(selected_streams) >= 1 else None
3631
+ destination_table = template_runtime_configuration.get('destination_table', stream)
3632
+
3633
+ global_vars['index'] = index
3634
+ global_vars['is_last_block_run'] = is_last_block_run
3635
+ global_vars['stream'] = stream
3636
+ global_vars['destination_table'] = destination_table
3678
3637
 
3679
3638
  return global_vars
3680
3639
 
@@ -0,0 +1,77 @@
1
+ from mage_ai.data_preparation.models.block import Block, CallbackBlock, ConditionalBlock
2
+ from mage_ai.data_preparation.models.block.constants import BLOCK_TYPE_TO_CLASS
3
+ from mage_ai.data_preparation.models.block.integration import (
4
+ DestinationBlock,
5
+ SourceBlock,
6
+ TransformerBlock,
7
+ )
8
+ from mage_ai.data_preparation.models.block.r import RBlock
9
+ from mage_ai.data_preparation.models.block.sql import SQLBlock
10
+ from mage_ai.data_preparation.models.constants import (
11
+ BlockLanguage,
12
+ BlockStatus,
13
+ BlockType,
14
+ PipelineType,
15
+ )
16
+ from mage_ai.data_preparation.models.widget import Widget
17
+
18
+ try:
19
+ from mage_ai.data_preparation.models.block.dbt.block_sql import DBTBlockSQL
20
+ from mage_ai.data_preparation.models.block.dbt.block_yaml import DBTBlockYAML
21
+ except Exception:
22
+ print('DBT library not installed.')
23
+
24
+
25
+ class BlockFactory:
26
+ @classmethod
27
+ def block_class_from_type(self, block_type: str, language=None, pipeline=None) -> 'Block':
28
+ if BlockType.CHART == block_type:
29
+ return Widget
30
+ elif BlockType.DBT == block_type:
31
+ if language == BlockLanguage.YAML:
32
+ return DBTBlockYAML
33
+ return DBTBlockSQL
34
+ elif pipeline and PipelineType.INTEGRATION == pipeline.type:
35
+ if BlockType.CALLBACK == block_type:
36
+ return CallbackBlock
37
+ elif BlockType.CONDITIONAL == block_type:
38
+ return ConditionalBlock
39
+ elif BlockType.DATA_LOADER == block_type:
40
+ return SourceBlock
41
+ elif BlockType.DATA_EXPORTER == block_type:
42
+ return DestinationBlock
43
+ else:
44
+ return TransformerBlock
45
+ elif BlockLanguage.SQL == language:
46
+ return SQLBlock
47
+ elif BlockLanguage.R == language:
48
+ return RBlock
49
+ return BLOCK_TYPE_TO_CLASS.get(block_type)
50
+
51
+ @classmethod
52
+ def get_block(
53
+ self,
54
+ name,
55
+ uuid,
56
+ block_type,
57
+ configuration=None,
58
+ content=None,
59
+ language=None,
60
+ pipeline=None,
61
+ status=BlockStatus.NOT_EXECUTED,
62
+ ) -> 'Block':
63
+ block_class = BlockFactory.block_class_from_type(
64
+ block_type,
65
+ language=language,
66
+ pipeline=pipeline,
67
+ ) or Block
68
+ return block_class(
69
+ name,
70
+ uuid,
71
+ block_type,
72
+ configuration=configuration,
73
+ content=content,
74
+ language=language,
75
+ pipeline=pipeline,
76
+ status=status,
77
+ )
@@ -26,19 +26,17 @@ from mage_ai.shared.parsers import encode_complex
26
26
 
27
27
 
28
28
  class DBTBlock(Block):
29
- def __new__(cls, *args, **kwargs) -> 'DBTBlock':
29
+ @classmethod
30
+ def create(cls, *args, **kwargs) -> 'DBTBlock':
30
31
  """
31
32
  Factory for the child blocks
32
33
  """
33
34
  # Import Child blocks here to prevent cycle import
34
35
  from mage_ai.data_preparation.models.block.dbt.block_sql import DBTBlockSQL
35
36
  from mage_ai.data_preparation.models.block.dbt.block_yaml import DBTBlockYAML
36
- if cls is DBTBlock:
37
- if kwargs.get('language', BlockLanguage.SQL) == BlockLanguage.YAML:
38
- return super(DBTBlock, cls).__new__(DBTBlockYAML)
39
- return super(DBTBlock, cls).__new__(DBTBlockSQL)
40
- else:
41
- return super(DBTBlock, cls).__new__(cls, *args, **kwargs)
37
+ if kwargs.get('language', BlockLanguage.SQL) == BlockLanguage.YAML:
38
+ return DBTBlockYAML(*args, **kwargs)
39
+ return DBTBlockSQL(*args, **kwargs)
42
40
 
43
41
  @property
44
42
  def base_project_path(self) -> Union[str, os.PathLike]:
@@ -2,12 +2,15 @@ from logging import Logger
2
2
  from typing import Dict, List
3
3
 
4
4
  from mage_ai.data_preparation.models.block import Block
5
- from mage_ai.data_preparation.models.global_data_product import GlobalDataProduct
6
- from mage_ai.orchestration.triggers import global_data_product as trigger
7
5
 
8
6
 
9
7
  class GlobalDataProductBlock(Block):
10
- def get_global_data_product(self) -> GlobalDataProduct:
8
+ def get_global_data_product(self):
9
+ # Avoid circular dependency of Pipeline class
10
+ from mage_ai.data_preparation.models.global_data_product import (
11
+ GlobalDataProduct,
12
+ )
13
+
11
14
  override_configuration = (self.configuration or {}).get('global_data_product', {})
12
15
  global_data_product = GlobalDataProduct.get(override_configuration.get('uuid'))
13
16
 
@@ -31,6 +34,9 @@ class GlobalDataProductBlock(Block):
31
34
  logging_tags: Dict = None,
32
35
  **kwargs,
33
36
  ) -> List:
37
+ # Avoid circular dependency of Pipeline class
38
+ from mage_ai.orchestration.triggers import global_data_product as trigger
39
+
34
40
  trigger.trigger_and_check_status(
35
41
  self.get_global_data_product(),
36
42
  block=self,
@@ -416,9 +416,10 @@ class SourceBlock(IntegrationBlock):
416
416
  class DestinationBlock(IntegrationBlock):
417
417
  def to_dict(
418
418
  self,
419
- include_content=False,
420
- include_outputs=False,
421
- sample_count=None,
419
+ include_content: bool = False,
420
+ include_outputs: bool = False,
421
+ include_block_pipelines: bool = False,
422
+ sample_count: int = None,
422
423
  check_if_file_exists: bool = False,
423
424
  destination_table: str = None,
424
425
  state_stream: str = None,
@@ -444,6 +445,7 @@ class DestinationBlock(IntegrationBlock):
444
445
  super().to_dict(
445
446
  include_content=include_content,
446
447
  include_outputs=include_outputs,
448
+ include_block_pipelines=include_block_pipelines,
447
449
  sample_count=sample_count,
448
450
  check_if_file_exists=check_if_file_exists,
449
451
  ),
@@ -452,9 +454,10 @@ class DestinationBlock(IntegrationBlock):
452
454
 
453
455
  async def to_dict_async(
454
456
  self,
455
- include_content=False,
456
- include_outputs=False,
457
- sample_count=None,
457
+ include_content: bool = False,
458
+ include_outputs: bool = False,
459
+ include_block_pipelines: bool = False,
460
+ sample_count: int = None,
458
461
  check_if_file_exists: bool = False,
459
462
  destination_table: str = None,
460
463
  state_stream: str = None,
@@ -463,13 +466,14 @@ class DestinationBlock(IntegrationBlock):
463
466
  return self.to_dict(
464
467
  include_content=include_content,
465
468
  include_outputs=include_outputs,
469
+ include_block_pipelines=include_block_pipelines,
466
470
  sample_count=sample_count,
467
471
  check_if_file_exists=check_if_file_exists,
468
472
  destination_table=destination_table,
469
473
  state_stream=state_stream,
470
474
  )
471
475
 
472
- def update(self, data, update_state=False):
476
+ def update(self, data, update_state=False, **kwargs):
473
477
  if update_state:
474
478
  from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
475
479
  IntegrationPipeline,
@@ -493,7 +497,7 @@ class DestinationBlock(IntegrationBlock):
493
497
  bookmark_values=bookmark_values
494
498
  )
495
499
 
496
- return super().update(data)
500
+ return super().update(data, **kwargs)
497
501
 
498
502
  def output_variables(self, execution_partition: str = None) -> List[str]:
499
503
  return []
@@ -233,7 +233,7 @@ class ProjectPlatformAccessible:
233
233
  ),
234
234
  )
235
235
 
236
- return block_class(
236
+ return block_class.create(
237
237
  name,
238
238
  uuid,
239
239
  block_type,
@@ -15,8 +15,10 @@ import yaml
15
15
  from jinja2 import Template
16
16
 
17
17
  from mage_ai.authentication.permissions.constants import EntityName
18
+ from mage_ai.cache.block import BlockCache
18
19
  from mage_ai.cache.pipeline import PipelineCache
19
20
  from mage_ai.data_preparation.models.block import Block, run_blocks, run_blocks_sync
21
+ from mage_ai.data_preparation.models.block.block_factory import BlockFactory
20
22
  from mage_ai.data_preparation.models.block.data_integration.utils import (
21
23
  convert_outputs_to_data,
22
24
  )
@@ -82,6 +84,8 @@ class Pipeline:
82
84
  repo_config=None,
83
85
  catalog=None,
84
86
  use_repo_path: bool = False,
87
+ description: str = None,
88
+ tags: List[str] = None,
85
89
  ):
86
90
  self.block_configs = []
87
91
  self.blocks_by_uuid = {}
@@ -90,7 +94,7 @@ class Pipeline:
90
94
  self.concurrency_config = dict()
91
95
  self.created_at = None
92
96
  self.data_integration = None
93
- self.description = None
97
+ self.description = description
94
98
  self.executor_config = dict()
95
99
  self.executor_type = None
96
100
  self.extensions = {}
@@ -101,7 +105,7 @@ class Pipeline:
101
105
  self.run_pipeline_in_one_process = False
102
106
  self.schedules = []
103
107
  self.settings = {}
104
- self.tags = []
108
+ self.tags = tags or []
105
109
  self.type = PipelineType.PYTHON
106
110
  self.use_repo_path = use_repo_path
107
111
  self.uuid = uuid
@@ -215,7 +219,14 @@ class Pipeline:
215
219
  self.widget_configs
216
220
 
217
221
  @classmethod
218
- def create(self, name, pipeline_type=PipelineType.PYTHON, repo_path=None):
222
+ def create(
223
+ self,
224
+ name: str,
225
+ description: str = None,
226
+ pipeline_type: PipelineType = PipelineType.PYTHON,
227
+ repo_path: str = None,
228
+ tags: List[str] = None,
229
+ ):
219
230
  """
220
231
  1. Create a new folder for pipeline
221
232
  2. Create a new yaml file to store pipeline config
@@ -231,14 +242,20 @@ class Pipeline:
231
242
  with open(os.path.join(pipeline_path, PIPELINE_CONFIG_FILE), 'w') as fp:
232
243
  yaml.dump(dict(
233
244
  created_at=str(datetime.now(tz=pytz.UTC)),
245
+ description=description,
234
246
  name=name,
247
+ tags=tags or [],
235
248
  uuid=uuid,
236
249
  type=format_enum(pipeline_type or PipelineType.PYTHON),
237
250
  ), fp)
251
+
238
252
  pipeline = Pipeline(
239
253
  uuid,
254
+ description=description,
240
255
  repo_path=repo_path,
256
+ tags=tags or [],
241
257
  )
258
+
242
259
  return pipeline
243
260
 
244
261
  @classmethod
@@ -368,6 +385,54 @@ class Pipeline:
368
385
  IntegrationPipeline,
369
386
  )
370
387
 
388
+ config_path, repo_path = self._get_config_path(
389
+ uuid,
390
+ repo_path=repo_path,
391
+ all_projects=all_projects,
392
+ use_repo_path=use_repo_path,
393
+ )
394
+
395
+ if check_if_exists and not os.path.exists(config_path):
396
+ return None
397
+
398
+ pipeline = self(uuid, repo_path=repo_path, use_repo_path=use_repo_path)
399
+ if PipelineType.INTEGRATION == pipeline.type:
400
+ pipeline = IntegrationPipeline(uuid, repo_path=repo_path)
401
+
402
+ return pipeline
403
+
404
+ @classmethod
405
+ def get_config(
406
+ self,
407
+ uuid,
408
+ repo_path: str = None,
409
+ all_projects: bool = False,
410
+ use_repo_path: bool = False,
411
+ ):
412
+ config_path, _ = self._get_config_path(
413
+ uuid,
414
+ repo_path=repo_path,
415
+ all_projects=all_projects,
416
+ use_repo_path=use_repo_path,
417
+ )
418
+
419
+ metadata_path = os.path.join(config_path, PIPELINE_CONFIG_FILE)
420
+
421
+ if not os.path.exists(metadata_path):
422
+ return None
423
+
424
+ with open(metadata_path) as fp:
425
+ config = yaml.full_load(fp) or {}
426
+ return config
427
+
428
+ @classmethod
429
+ def _get_config_path(
430
+ self,
431
+ uuid,
432
+ repo_path: str = None,
433
+ all_projects: bool = False,
434
+ use_repo_path: bool = False,
435
+ ) -> Tuple[str, str]:
371
436
  if all_projects and not use_repo_path and project_platform_activated():
372
437
  from mage_ai.settings.platform.utils import get_pipeline_config_path
373
438
 
@@ -379,15 +444,7 @@ class Pipeline:
379
444
  PIPELINES_FOLDER,
380
445
  uuid,
381
446
  )
382
-
383
- if check_if_exists and not os.path.exists(config_path):
384
- return None
385
-
386
- pipeline = self(uuid, repo_path=repo_path, use_repo_path=use_repo_path)
387
- if PipelineType.INTEGRATION == pipeline.type:
388
- pipeline = IntegrationPipeline(uuid, repo_path=repo_path)
389
-
390
- return pipeline
447
+ return config_path, repo_path
391
448
 
392
449
  @classmethod
393
450
  async def load_metadata(
@@ -717,7 +774,8 @@ class Pipeline:
717
774
  )
718
775
 
719
776
  language = c.get('language')
720
- return Block.block_class_from_type(block_type, language=language, pipeline=self)(
777
+
778
+ return BlockFactory.block_class_from_type(block_type, language=language, pipeline=self)(
721
779
  c.get('name'),
722
780
  c.get('uuid'),
723
781
  block_type,
@@ -931,6 +989,8 @@ class Pipeline:
931
989
  include_outputs=include_outputs,
932
990
  sample_count=sample_count,
933
991
  )
992
+ if include_block_pipelines:
993
+ shared_kwargs['block_cache'] = BlockCache()
934
994
  blocks_data = await asyncio.gather(
935
995
  *[b.to_dict_async(**merge_dict(shared_kwargs, dict(
936
996
  include_block_catalog=include_block_catalog,
@@ -991,6 +1051,7 @@ class Pipeline:
991
1051
  old_uuid = None
992
1052
  blocks_to_remove_from_cache = []
993
1053
  block_uuids_to_add_to_cache = []
1054
+ tags_to_remove_from_cache = []
994
1055
  should_update_block_cache = False
995
1056
  should_update_tag_cache = False
996
1057
 
@@ -1043,6 +1104,10 @@ class Pipeline:
1043
1104
  old_tags = self.tags or []
1044
1105
 
1045
1106
  if sorted(new_tags) != sorted(old_tags):
1107
+ tags_diff = set(old_tags).symmetric_difference(set(new_tags))
1108
+ for tag in tags_diff:
1109
+ if tag in old_tags:
1110
+ tags_to_remove_from_cache.append(tag)
1046
1111
  self.tags = new_tags
1047
1112
  should_save = True
1048
1113
  should_update_tag_cache = True
@@ -1296,6 +1361,8 @@ class Pipeline:
1296
1361
 
1297
1362
  cache = await TagCache.initialize_cache()
1298
1363
 
1364
+ for tag_uuid in tags_to_remove_from_cache:
1365
+ cache.remove_pipeline(tag_uuid, self.uuid, self.repo_path)
1299
1366
  for tag_uuid in self.tags:
1300
1367
  if old_uuid:
1301
1368
  cache.remove_pipeline(tag_uuid, old_uuid, self.repo_path)
@@ -29,11 +29,36 @@ class GCSStorage(BaseStorage):
29
29
  path += '/'
30
30
  return self.path_exists(path)
31
31
 
32
- def listdir(self, path: str, suffix: str = None) -> List[str]:
32
+ def listdir(
33
+ self,
34
+ path: str,
35
+ suffix: str = None,
36
+ max_results: int = None,
37
+ ) -> List[str]:
33
38
  if not path.endswith('/'):
34
39
  path += '/'
35
40
  path = gcs_url_path(path)
36
- blobs = self.bucket.list_blobs(prefix=path)
41
+
42
+ """
43
+ NOTE: The number of results returned by the GCS bucket list_blobs method may
44
+ be lower than the number entered for the max_results argument, since this
45
+ method recursively fetches files inside of subdirectories at the path
46
+ specified, not just the directories themselves at the top level of the path.
47
+
48
+ As a result, when fetching block output folders in a remote variables directory,
49
+ the json or parquet files inside of the block output folders (e.g. the "type.json"
50
+ file in folder "output_0") are counted towards the "max_results" limit. If max_results
51
+ is set to 10, less than 10 output folders may be returned due to there being multiple
52
+ json or other files in each output folder. We do not increase the max_results or
53
+ include a "delimiter" argument because it would increase load times to unacceptable levels.
54
+
55
+ Example block output path in GCS:
56
+ gs://mage_demo/pipelines/example_pipeline/.variables/example_block/output_0/
57
+ """
58
+ blobs = self.bucket.list_blobs(
59
+ prefix=path,
60
+ max_results=max_results,
61
+ )
37
62
  keys = []
38
63
  for blob in blobs:
39
64
  # Avoid finding files recursevively in the dir path.
@@ -123,7 +148,7 @@ class GCSStorage(BaseStorage):
123
148
  df.write_parquet(buffer)
124
149
  buffer.seek(0)
125
150
  blob = self.bucket.blob(gcs_url_path(file_path))
126
- blob.upload_from_string(buffer)
151
+ blob.upload_from_string(buffer.getvalue())
127
152
 
128
153
  @contextmanager
129
154
  def open_to_write(self, file_path: str) -> None: