mage-ai 0.9.65__py3-none-any.whl → 0.9.67__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 (242) hide show
  1. mage_ai/api/monitors/BaseMonitor.py +38 -16
  2. mage_ai/api/policies/BackfillPolicy.py +1 -0
  3. mage_ai/api/resources/OauthResource.py +13 -5
  4. mage_ai/api/resources/SessionResource.py +6 -4
  5. mage_ai/authentication/ldap.py +19 -9
  6. mage_ai/authentication/oauth/constants.py +8 -14
  7. mage_ai/authentication/oauth/utils.py +18 -6
  8. mage_ai/authentication/providers/active_directory.py +21 -16
  9. mage_ai/authentication/providers/azure_devops.py +18 -0
  10. mage_ai/authentication/providers/bitbucket.py +10 -9
  11. mage_ai/authentication/providers/constants.py +2 -0
  12. mage_ai/authentication/providers/ghe.py +5 -9
  13. mage_ai/authentication/providers/gitlab.py +6 -9
  14. mage_ai/authentication/providers/google.py +9 -6
  15. mage_ai/authentication/providers/oidc.py +6 -4
  16. mage_ai/authentication/providers/okta.py +9 -6
  17. mage_ai/cluster_manager/kubernetes/workload_manager.py +10 -0
  18. mage_ai/cluster_manager/workspace/base.py +6 -1
  19. mage_ai/cluster_manager/workspace/kubernetes.py +3 -0
  20. mage_ai/data_preparation/decorators.py +15 -0
  21. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +22 -12
  22. mage_ai/data_preparation/git/__init__.py +10 -1
  23. mage_ai/data_preparation/git/api.py +3 -0
  24. mage_ai/data_preparation/git/clients/azure_devops.py +106 -0
  25. mage_ai/data_preparation/git/clients/base.py +6 -0
  26. mage_ai/data_preparation/git/clients/gitlab.py +3 -2
  27. mage_ai/data_preparation/git/utils.py +31 -29
  28. mage_ai/data_preparation/models/block/__init__.py +27 -18
  29. mage_ai/data_preparation/models/block/dbt/block_sql.py +164 -0
  30. mage_ai/data_preparation/models/block/dynamic/variables.py +1 -2
  31. mage_ai/data_preparation/models/pipeline.py +3 -3
  32. mage_ai/data_preparation/models/triggers/__init__.py +6 -1
  33. mage_ai/data_preparation/preferences.py +42 -37
  34. mage_ai/data_preparation/repo_manager.py +21 -0
  35. mage_ai/data_preparation/storage/gcs_storage.py +27 -2
  36. mage_ai/data_preparation/storage/local_storage.py +18 -3
  37. mage_ai/data_preparation/storage/s3_storage.py +7 -2
  38. mage_ai/data_preparation/templates/data_loaders/streaming/generic_python.py +23 -0
  39. mage_ai/data_preparation/templates/main/metadata.yaml +6 -0
  40. mage_ai/data_preparation/templates/template.py +6 -2
  41. mage_ai/data_preparation/variable_manager.py +2 -1
  42. mage_ai/io/base.py +3 -0
  43. mage_ai/io/bigquery.py +2 -0
  44. mage_ai/io/export_utils.py +14 -9
  45. mage_ai/io/mssql.py +104 -25
  46. mage_ai/io/mysql.py +10 -9
  47. mage_ai/io/oracledb.py +14 -2
  48. mage_ai/io/postgres.py +3 -0
  49. mage_ai/io/sql.py +14 -6
  50. mage_ai/io/trino.py +10 -8
  51. mage_ai/orchestration/db/migrations/versions/90d978a8aef8_update_unique_constraint_for_secret.py +11 -5
  52. mage_ai/orchestration/db/models/schedules.py +25 -1
  53. mage_ai/orchestration/db/models/schedules_project_platform.py +24 -1
  54. mage_ai/orchestration/job_manager.py +6 -1
  55. mage_ai/orchestration/pipeline_scheduler_original.py +16 -10
  56. mage_ai/server/constants.py +1 -1
  57. mage_ai/server/file_observer.py +10 -0
  58. mage_ai/server/frontend_dist/404.html +2 -2
  59. mage_ai/server/frontend_dist/_next/static/chunks/{1557-a754b04510d50b80.js → 1557-01f0843dc6ac4971.js} +1 -1
  60. mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-30e34ee15d410331.js +1 -0
  64. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +1 -0
  65. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +1 -0
  66. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{edit-8d32ac7e8f023779.js → edit-36377e679da2cd91.js} +1 -1
  67. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-fe08120d9a6fb1b0.js → triggers-f508c2f261297724.js} +1 -1
  69. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-bcdb4ad41dd4c7d5.js → frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js} +1 -1
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/{sign-in-19b36600d908b711.js → sign-in-7d38b2f7c3e918a1.js} +1 -1
  71. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +1 -0
  72. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-ac7fdc472bedf682.js → webpack-d079359c241db804.js} +1 -1
  73. mage_ai/server/frontend_dist/_next/static/{ZMrJfDouIX5AMb_RteRbL → vPsMu6Fi2zrHaf2fRXKRO}/_buildManifest.js +1 -1
  74. mage_ai/server/frontend_dist/block-layout.html +2 -2
  75. mage_ai/server/frontend_dist/compute.html +2 -2
  76. mage_ai/server/frontend_dist/files.html +2 -2
  77. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  78. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  79. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  80. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  81. mage_ai/server/frontend_dist/index.html +2 -2
  82. mage_ai/server/frontend_dist/manage/files.html +2 -2
  83. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  84. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  85. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  86. mage_ai/server/frontend_dist/manage/users.html +2 -2
  87. mage_ai/server/frontend_dist/manage.html +2 -2
  88. mage_ai/server/frontend_dist/oauth.html +2 -2
  89. mage_ai/server/frontend_dist/overview.html +2 -2
  90. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  91. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  92. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  93. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  94. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  95. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  96. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  97. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  98. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  99. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  100. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  101. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  102. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  103. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  104. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  105. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  106. mage_ai/server/frontend_dist/pipelines.html +2 -2
  107. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  108. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  109. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  110. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  111. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  112. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  113. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  114. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  115. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  116. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  117. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  118. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  119. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  120. mage_ai/server/frontend_dist/settings.html +2 -2
  121. mage_ai/server/frontend_dist/sign-in.html +2 -2
  122. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  123. mage_ai/server/frontend_dist/templates.html +2 -2
  124. mage_ai/server/frontend_dist/terminal.html +2 -2
  125. mage_ai/server/frontend_dist/test.html +2 -2
  126. mage_ai/server/frontend_dist/triggers.html +2 -2
  127. mage_ai/server/frontend_dist/version-control.html +2 -2
  128. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  129. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1557-a754b04510d50b80.js → 1557-01f0843dc6ac4971.js} +1 -1
  130. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +1 -0
  131. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +1 -0
  132. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +1 -0
  133. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-30e34ee15d410331.js +1 -0
  134. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +1 -0
  135. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +1 -0
  136. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{edit-8d32ac7e8f023779.js → edit-36377e679da2cd91.js} +1 -1
  137. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
  138. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-fe08120d9a6fb1b0.js → triggers-f508c2f261297724.js} +1 -1
  139. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines-bcdb4ad41dd4c7d5.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js} +1 -1
  140. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{sign-in-19b36600d908b711.js → sign-in-7d38b2f7c3e918a1.js} +1 -1
  141. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +1 -0
  142. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-481689d9989710cd.js → webpack-68c003fb6a175cd7.js} +1 -1
  143. mage_ai/server/frontend_dist_base_path_template/_next/static/{QYwFH4sievaq5XyUjRriy → khKiaJtwrslgMmp4YSa1f}/_buildManifest.js +1 -1
  144. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  145. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  146. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  147. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  148. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  149. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  150. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  151. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  152. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  153. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  154. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  155. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  156. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  157. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  158. mage_ai/server/frontend_dist_base_path_template/oauth.html +2 -2
  159. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  160. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  161. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  162. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  163. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  164. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  165. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  166. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  167. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  168. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  169. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  172. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  173. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  181. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  183. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  188. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  191. mage_ai/server/frontend_dist_base_path_template/sign-in.html +2 -2
  192. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  193. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  194. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  195. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  196. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  197. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  198. mage_ai/server/server.py +117 -87
  199. mage_ai/server/utils/output_display.py +6 -1
  200. mage_ai/services/aws/s3/s3.py +8 -2
  201. mage_ai/services/slack/slack.py +8 -8
  202. mage_ai/settings/__init__.py +36 -186
  203. mage_ai/settings/backends.py +95 -0
  204. mage_ai/settings/keys/__init__.py +1 -0
  205. mage_ai/settings/keys/auth.py +76 -0
  206. mage_ai/settings/server.py +187 -0
  207. mage_ai/shared/io.py +2 -2
  208. mage_ai/shared/logger.py +12 -6
  209. mage_ai/streaming/sources/base_python.py +30 -0
  210. mage_ai/streaming/sources/source_factory.py +25 -0
  211. mage_ai/tests/api/endpoints/test_oauths.py +13 -5
  212. mage_ai/tests/api/operations/test_operations.py +2 -2
  213. mage_ai/tests/api/operations/test_sessions.py +83 -48
  214. mage_ai/tests/authentication/oauth/test_utils.py +56 -6
  215. mage_ai/tests/authentication/providers/test_active_directory.py +9 -15
  216. mage_ai/tests/data_preparation/models/test_block.py +39 -2
  217. mage_ai/tests/orchestration/db/models/test_schedules.py +33 -1
  218. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/METADATA +2 -1
  219. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/RECORD +225 -217
  220. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/WHEEL +1 -1
  221. mage_ai/server/frontend_dist/_next/static/chunks/9440-2bcbdc765ed82062.js +0 -1
  222. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2ae1d919333f01fe.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/oauth-abe5ba687cb93509.js +0 -1
  225. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-22e49726eeed16ae.js +0 -1
  226. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c74507dce89b41a2.js +0 -1
  227. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
  228. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-690206d30d8b412b.js +0 -1
  229. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-2bcbdc765ed82062.js +0 -1
  230. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2ae1d919333f01fe.js +0 -1
  231. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
  232. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-abe5ba687cb93509.js +0 -1
  233. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-22e49726eeed16ae.js +0 -1
  234. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c74507dce89b41a2.js +0 -1
  235. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
  236. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-690206d30d8b412b.js +0 -1
  237. mage_ai/settings/sso.py +0 -27
  238. /mage_ai/server/frontend_dist/_next/static/{ZMrJfDouIX5AMb_RteRbL → vPsMu6Fi2zrHaf2fRXKRO}/_ssgManifest.js +0 -0
  239. /mage_ai/server/frontend_dist_base_path_template/_next/static/{QYwFH4sievaq5XyUjRriy → khKiaJtwrslgMmp4YSa1f}/_ssgManifest.js +0 -0
  240. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/LICENSE +0 -0
  241. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/entry_points.txt +0 -0
  242. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/top_level.txt +0 -0
@@ -9,14 +9,17 @@ from mage_ai.authentication.oauth.constants import ProviderName
9
9
  from mage_ai.authentication.providers.oauth import OauthProvider
10
10
  from mage_ai.authentication.providers.sso import SsoProvider
11
11
  from mage_ai.authentication.providers.utils import get_base_url
12
- from mage_ai.settings.sso import OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_DOMAIN_URL
12
+ from mage_ai.settings import get_settings_value
13
+ from mage_ai.settings.keys import OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_DOMAIN_URL
13
14
 
14
15
 
15
16
  class OktaProvider(SsoProvider, OauthProvider):
16
17
  provider = ProviderName.OKTA
17
18
 
18
19
  def __init__(self):
19
- self.hostname = OKTA_DOMAIN_URL
20
+ self.hostname = get_settings_value(OKTA_DOMAIN_URL)
21
+ self.client_id = get_settings_value(OKTA_CLIENT_ID)
22
+ self.client_secret = get_settings_value(OKTA_CLIENT_SECRET)
20
23
  self.__validate()
21
24
 
22
25
  if not self.hostname.startswith('https'):
@@ -27,11 +30,11 @@ class OktaProvider(SsoProvider, OauthProvider):
27
30
  raise Exception(
28
31
  'Okta hostname is empty. '
29
32
  'Make sure the OKTA_DOMAIN_URL environment variable is set.')
30
- if not OKTA_CLIENT_ID:
33
+ if not self.client_id:
31
34
  raise Exception(
32
35
  'Okta client id is empty. '
33
36
  'Make sure the OKTA_CLIENT_ID environment variable is set.')
34
- if not OKTA_CLIENT_SECRET:
37
+ if not self.client_secret:
35
38
  raise Exception(
36
39
  'Okta client secret is empty. '
37
40
  'Make sure the OKTA_CLIENT_SECRET environment variable is set.')
@@ -43,7 +46,7 @@ class OktaProvider(SsoProvider, OauthProvider):
43
46
  redirect_uri=redirect_uri,
44
47
  )
45
48
  query = dict(
46
- client_id=OKTA_CLIENT_ID,
49
+ client_id=self.client_id,
47
50
  redirect_uri=urllib.parse.quote_plus(
48
51
  f'{base_url}/oauth',
49
52
  ),
@@ -75,7 +78,7 @@ class OktaProvider(SsoProvider, OauthProvider):
75
78
  code=code,
76
79
  redirect_uri=f'{base_url}/oauth',
77
80
  ),
78
- auth=BasicAuth(OKTA_CLIENT_ID, OKTA_CLIENT_SECRET),
81
+ auth=BasicAuth(self.client_id, self.client_secret),
79
82
  timeout=20,
80
83
  ) as response:
81
84
  data = await response.json()
@@ -199,6 +199,7 @@ class WorkloadManager:
199
199
  self,
200
200
  name: str,
201
201
  workspace_config: KubernetesWorkspaceConfig,
202
+ initial_metadata: Dict = None,
202
203
  project_type: str = ProjectType.STANDALONE,
203
204
  ):
204
205
  """
@@ -245,6 +246,7 @@ class WorkloadManager:
245
246
  project_uuid=workspace_config.project_uuid,
246
247
  container_config=container_config,
247
248
  set_base_path=ingress_name is not None,
249
+ initial_metadata=initial_metadata,
248
250
  )
249
251
  container_config['env'] = env_vars
250
252
 
@@ -713,6 +715,7 @@ class WorkloadManager:
713
715
  project_type: str = 'standalone',
714
716
  project_uuid: str = None,
715
717
  container_config: Dict = None,
718
+ initial_metadata: Dict = None,
716
719
  set_base_path: bool = False,
717
720
  ) -> List:
718
721
  env_vars = [
@@ -746,6 +749,13 @@ class WorkloadManager:
746
749
  'value': project_uuid,
747
750
  }
748
751
  )
752
+ if initial_metadata:
753
+ env_vars.append(
754
+ {
755
+ 'name': 'INITIAL_METADATA',
756
+ 'value': json.dumps(initial_metadata),
757
+ }
758
+ )
749
759
 
750
760
  connection_url_secrets_name = os.getenv(CONNECTION_URL_SECRETS_NAME)
751
761
  if connection_url_secrets_name:
@@ -6,7 +6,11 @@ from typing import Dict, Optional
6
6
  from mage_ai.cluster_manager.config import LifecycleConfig, WorkspaceConfig
7
7
  from mage_ai.cluster_manager.constants import ClusterType
8
8
  from mage_ai.cluster_manager.errors import WorkspaceExistsError
9
- from mage_ai.data_preparation.repo_manager import ProjectType, get_project_type
9
+ from mage_ai.data_preparation.repo_manager import (
10
+ ProjectType,
11
+ get_project_type,
12
+ get_repo_config,
13
+ )
10
14
  from mage_ai.orchestration.constants import Entity
11
15
  from mage_ai.orchestration.db import db_connection, safe_db_query
12
16
  from mage_ai.orchestration.db.models.oauth import Permission, User
@@ -115,6 +119,7 @@ class Workspace(abc.ABC):
115
119
 
116
120
  project_uuid = uuid.uuid4().hex
117
121
  data['project_uuid'] = project_uuid
122
+ data['workspace_initial_metadata'] = get_repo_config().workspace_initial_metadata
118
123
 
119
124
  workspace_class = cls.workspace_class_from_type(cluster_type)
120
125
 
@@ -49,6 +49,7 @@ class KubernetesWorkspace(Workspace):
49
49
  Workspace: An initialized Workspace object.
50
50
  """
51
51
  namespace = kwargs.pop('namespace', os.getenv(KUBE_NAMESPACE))
52
+ workspace_initial_metadata = kwargs.pop('workspace_initial_metadata', {})
52
53
  workspace_config = KubernetesWorkspaceConfig.load(
53
54
  config=merge_dict(
54
55
  kwargs,
@@ -70,7 +71,9 @@ class KubernetesWorkspace(Workspace):
70
71
  if get_project_type() == ProjectType.MAIN:
71
72
  extra_args = {
72
73
  'project_type': ProjectType.SUB,
74
+ 'initial_metadata': workspace_initial_metadata,
73
75
  }
76
+
74
77
  workload_manager.create_workload(
75
78
  name,
76
79
  workspace_config,
@@ -103,3 +103,18 @@ def data_integration_query(function):
103
103
 
104
104
  def preprocesser_functions(function):
105
105
  return function
106
+
107
+
108
+ def streaming_source(cls):
109
+ return cls
110
+
111
+
112
+ def collect_decorated_objs(decorated_objs):
113
+ """
114
+ Method to collect the decorated objects (function or class)
115
+ """
116
+ def custom_code(obj):
117
+ decorated_objs.append(obj)
118
+ return obj
119
+
120
+ return custom_code
@@ -10,7 +10,7 @@ from jinja2 import Template
10
10
 
11
11
  from mage_ai.data_preparation.executors.pipeline_executor import PipelineExecutor
12
12
  from mage_ai.data_preparation.logging.logger import DictLogger
13
- from mage_ai.data_preparation.models.constants import BlockType
13
+ from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
14
14
  from mage_ai.data_preparation.models.pipeline import Pipeline
15
15
  from mage_ai.data_preparation.shared.stream import StreamToLogger
16
16
  from mage_ai.data_preparation.shared.utils import get_template_vars
@@ -107,18 +107,28 @@ class StreamingPipelineExecutor(PipelineExecutor):
107
107
 
108
108
  if global_vars is None:
109
109
  global_vars = dict()
110
- source_config = self.__interpolate_vars(
111
- self.source_block.content,
112
- global_vars=global_vars,
113
- )
114
- source = SourceFactory.get_source(
115
- source_config,
116
- checkpoint_path=os.path.join(
117
- self.pipeline.pipeline_variables_dir,
118
- 'streaming_checkpoint',
119
- ),
120
- )
121
110
 
111
+ # Initialize source block
112
+ if self.source_block.language == BlockLanguage.PYTHON:
113
+ source = SourceFactory.get_python_source(
114
+ self.source_block.content,
115
+ global_vars=global_vars,
116
+ )
117
+ else:
118
+ # Default to YAML config
119
+ source_config = self.__interpolate_vars(
120
+ self.source_block.content,
121
+ global_vars=global_vars,
122
+ )
123
+ source = SourceFactory.get_source(
124
+ source_config,
125
+ checkpoint_path=os.path.join(
126
+ self.pipeline.pipeline_variables_dir,
127
+ 'streaming_checkpoint',
128
+ ),
129
+ )
130
+
131
+ # Initialize destination blocks
122
132
  sinks_by_uuid = dict()
123
133
  for sink_block in self.sink_blocks:
124
134
  sinks_by_uuid[sink_block.uuid] = SinkFactory.get_sink(
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from typing import Any, Callable, Dict, List
9
9
  from urllib.parse import urlparse, urlsplit, urlunsplit
10
10
 
11
+ from mage_ai.authentication.oauth.constants import ProviderName
11
12
  from mage_ai.data_preparation.git.constants import DEFAULT_KNOWN_HOSTS_FILE
12
13
  from mage_ai.data_preparation.git.utils import (
13
14
  add_host_to_known_hosts as add_host_to_known_hosts_util,
@@ -18,6 +19,7 @@ from mage_ai.data_preparation.git.utils import (
18
19
  check_connection_async,
19
20
  create_ssh_keys,
20
21
  get_access_token,
22
+ get_provider_from_remote_url,
21
23
  poll_process_with_timeout,
22
24
  run_command,
23
25
  )
@@ -622,7 +624,14 @@ class Git:
622
624
  try:
623
625
  for url in remote.urls:
624
626
  if url.lower().startswith('https'):
625
- repository_names.append('/'.join(url.split('/')[-2:]).replace('.git', ''))
627
+ provider = get_provider_from_remote_url(url)
628
+ if provider == ProviderName.AZURE_DEVOPS:
629
+ updated_url = url.replace('/_git', '')
630
+ repository_names.append('/'.join(updated_url.split('/')[-2:]))
631
+ else:
632
+ repository_names.append(
633
+ '/'.join(url.split('/')[-2:]).replace('.git', '')
634
+ )
626
635
 
627
636
  # Remove the token from the URL
628
637
  # e.g. https://[user]:[token]@[netloc]
@@ -15,8 +15,10 @@ from mage_ai.data_preparation.git.utils import (
15
15
  )
16
16
  from mage_ai.data_preparation.repo_manager import get_project_uuid
17
17
  from mage_ai.orchestration.db.models.oauth import Oauth2AccessToken, User
18
+ from mage_ai.server.logger import Logger
18
19
 
19
20
  API_ENDPOINT = 'https://api.github.com'
21
+ logger = Logger().new_server_logger(__name__)
20
22
 
21
23
 
22
24
  def get_oauth_client_id(provider: str) -> str:
@@ -262,4 +264,5 @@ def get_user(token: str, provider: str = ProviderName.GITHUB) -> Dict:
262
264
  try:
263
265
  return GitClient.get_client_for_provider(provider)(token).get_user()
264
266
  except Exception:
267
+ logger.exception('Error fetching user from git provider.')
265
268
  return dict()
@@ -0,0 +1,106 @@
1
+ import json
2
+
3
+ import requests
4
+
5
+ from mage_ai.data_preparation.git.clients.base import Client
6
+ from mage_ai.settings import get_settings_value
7
+ from mage_ai.settings.keys import AZURE_DEVOPS_ORGANIZATION
8
+
9
+
10
+ class AzureDevopsClient(Client):
11
+ def __init__(self, access_token: str):
12
+ super().__init__(access_token)
13
+ self.organization = get_settings_value(AZURE_DEVOPS_ORGANIZATION)
14
+
15
+ def get_user(self):
16
+ return dict(username='oauth2')
17
+
18
+ def get_branches(self, repository_name: str):
19
+ project_name, repository_name = repository_name.split('/')
20
+ resp = requests.get(
21
+ f'https://dev.azure.com/{self.organization}/{project_name}/_apis/git/repositories/{repository_name}/refs?api-version=7.1-preview.1', # noqa: E501
22
+ headers={
23
+ 'Accept': 'application/json',
24
+ 'Authorization': f'Bearer {self.access_token}',
25
+ },
26
+ timeout=10,
27
+ )
28
+ data = resp.json()
29
+
30
+ arr = []
31
+ for branch in data.get('value', []):
32
+ branch_name = branch.get('name')
33
+ if branch_name.startswith('refs/heads/'):
34
+ arr.append(branch_name)
35
+ return arr
36
+
37
+ def get_pull_requests(self, repository_name: str):
38
+ project_name, repository_name = repository_name.split('/')
39
+ resp = requests.get(
40
+ f'https://dev.azure.com/{self.organization}/{project_name}/_apis/git/repositories/{repository_name}/pullrequests?api-version=7.1-preview.1', # noqa: E501
41
+ headers={
42
+ 'Accept': 'application/json',
43
+ 'Authorization': f'Bearer {self.access_token}',
44
+ },
45
+ timeout=10,
46
+ )
47
+ data = resp.json()
48
+
49
+ arr = []
50
+ for pr in data.get('value', []):
51
+ arr.append(
52
+ dict(
53
+ body=pr.get('description'),
54
+ created_at=pr.get('creationDate'),
55
+ id=pr.get('pullRequestId'),
56
+ is_merged=pr.get('status') == 'completed',
57
+ merged=pr.get('status') == 'completed',
58
+ state=pr.get('status'),
59
+ title=pr.get('title'),
60
+ url=f'https://dev.azure.com/{self.organization}/{project_name}/_git/{repository_name}/pullrequest/{pr.get("pullRequestId")}', # noqa: E501
61
+ user=pr.get('createdBy', {}).get('displayName'),
62
+ )
63
+ )
64
+
65
+ return arr
66
+
67
+ def create_pull_request(
68
+ self,
69
+ repository_name: str,
70
+ base_branch: str,
71
+ body: str,
72
+ compare_branch: str,
73
+ title: str,
74
+ ):
75
+ project_name, repository_name = repository_name.split('/')
76
+ data = {
77
+ 'title': title,
78
+ 'description': body,
79
+ 'sourceRefName': compare_branch,
80
+ 'targetRefName': base_branch,
81
+ }
82
+
83
+ resp = requests.post(
84
+ f'https://dev.azure.com/{self.organization}/{project_name}/_apis/git/repositories/{repository_name}/pullrequests?api-version=7.1-preview.1', # noqa: E501
85
+ headers={
86
+ 'Accept': 'application/json',
87
+ 'Authorization': f'Bearer {self.access_token}',
88
+ 'Content-Type': 'application/json',
89
+ },
90
+ data=json.dumps(data),
91
+ timeout=10,
92
+ )
93
+
94
+ resp.raise_for_status()
95
+ pr = resp.json()
96
+ return dict(
97
+ body=pr.get('description'),
98
+ created_at=pr.get('creationDate'),
99
+ id=pr.get('pullRequestId'),
100
+ is_merged=pr.get('status') == 'completed',
101
+ merged=pr.get('status') == 'completed',
102
+ state=pr.get('status'),
103
+ title=pr.get('title'),
104
+ url=pr.get('url'),
105
+ user=pr.get('createdBy', {}).get('displayName'),
106
+ )
@@ -25,6 +25,12 @@ class Client(ABC):
25
25
  from mage_ai.data_preparation.git.clients.ghe import GHEClient
26
26
 
27
27
  return GHEClient
28
+ elif provider == ProviderName.AZURE_DEVOPS:
29
+ from mage_ai.data_preparation.git.clients.azure_devops import (
30
+ AzureDevopsClient,
31
+ )
32
+
33
+ return AzureDevopsClient
28
34
  else:
29
35
  raise NotImplementedError()
30
36
 
@@ -3,14 +3,15 @@ from urllib.parse import quote_plus
3
3
 
4
4
  import requests
5
5
 
6
- from mage_ai.authentication.oauth.constants import GITLAB_HOST
7
6
  from mage_ai.data_preparation.git.clients.base import Client
7
+ from mage_ai.settings import get_settings_value
8
+ from mage_ai.settings.keys import GITLAB_HOST
8
9
 
9
10
 
10
11
  class GitlabClient(Client):
11
12
  def __init__(self, access_token: str):
12
13
  super().__init__(access_token)
13
- self.hostname = GITLAB_HOST or 'https://gitlab.com'
14
+ self.hostname = get_settings_value(GITLAB_HOST, 'https://gitlab.com')
14
15
 
15
16
  def get_user(self):
16
17
  # For GitLab, we don't need to make a request to the API to get the username
@@ -5,21 +5,21 @@ import subprocess
5
5
  from typing import Callable
6
6
  from urllib.parse import urlparse, urlsplit, urlunsplit
7
7
 
8
- from mage_ai.authentication.oauth.constants import (
9
- BITBUCKET_HOST,
10
- GITLAB_HOST,
11
- ProviderName,
12
- get_ghe_hostname,
13
- )
8
+ from mage_ai.authentication.oauth.constants import ProviderName, get_ghe_hostname
14
9
  from mage_ai.data_preparation.git.constants import (
15
10
  DEFAULT_KNOWN_HOSTS_FILE,
16
11
  DEFAULT_SSH_KEY_DIRECTORY,
17
- GIT_ACCESS_TOKEN_VAR,
18
- GIT_SSH_PRIVATE_KEY_VAR,
19
- GIT_SSH_PUBLIC_KEY_VAR,
20
12
  )
21
13
  from mage_ai.data_preparation.shared.secrets import get_secret_value
22
14
  from mage_ai.data_preparation.sync import AuthType, GitConfig
15
+ from mage_ai.settings import get_settings_value
16
+ from mage_ai.settings.keys import (
17
+ BITBUCKET_HOST,
18
+ GIT_ACCESS_TOKEN,
19
+ GIT_SSH_PRIVATE_KEY,
20
+ GIT_SSH_PUBLIC_KEY,
21
+ GITLAB_HOST,
22
+ )
23
23
  from mage_ai.settings.repo import get_repo_path
24
24
 
25
25
 
@@ -38,10 +38,14 @@ def get_provider_from_remote_url(remote_url: str) -> str:
38
38
  if not remote_url:
39
39
  return ProviderName.GITHUB
40
40
 
41
- if BITBUCKET_HOST and BITBUCKET_HOST in remote_url or 'bitbucket.org' in remote_url:
41
+ bitbucket_host = get_settings_value(BITBUCKET_HOST)
42
+ gitlab_host = get_settings_value(GITLAB_HOST)
43
+ if bitbucket_host and bitbucket_host in remote_url or 'bitbucket.org' in remote_url:
42
44
  return ProviderName.BITBUCKET
43
- elif GITLAB_HOST and GITLAB_HOST in remote_url or 'gitlab.com' in remote_url:
45
+ elif gitlab_host and gitlab_host in remote_url or 'gitlab.com' in remote_url:
44
46
  return ProviderName.GITLAB
47
+ elif 'dev.azure.com' in remote_url:
48
+ return ProviderName.AZURE_DEVOPS
45
49
  elif ghe_hostname and ghe_hostname in remote_url:
46
50
  return ProviderName.GHE
47
51
  else:
@@ -59,13 +63,13 @@ def create_ssh_keys(git_config: GitConfig, repo_path: str, overwrite: bool = Fal
59
63
  )
60
64
  if not os.path.exists(public_key_file) or overwrite:
61
65
  try:
62
- public_key = get_secret_value(
63
- pubk_secret_name,
64
- repo_name=repo_path,
65
- suppress_warning=True,
66
- )
67
- if os.getenv(GIT_SSH_PUBLIC_KEY_VAR):
68
- public_key = os.getenv(GIT_SSH_PUBLIC_KEY_VAR)
66
+ public_key = get_settings_value(GIT_SSH_PUBLIC_KEY)
67
+ if not public_key:
68
+ public_key = get_secret_value(
69
+ pubk_secret_name,
70
+ repo_name=repo_path,
71
+ suppress_warning=True,
72
+ )
69
73
  if public_key:
70
74
  with open(public_key_file, 'w') as f:
71
75
  f.write(base64.b64decode(public_key).decode('utf-8'))
@@ -81,13 +85,13 @@ def create_ssh_keys(git_config: GitConfig, repo_path: str, overwrite: bool = Fal
81
85
  )
82
86
  if not os.path.exists(custom_private_key_file) or overwrite:
83
87
  try:
84
- private_key = get_secret_value(
85
- pk_secret_name,
86
- repo_name=repo_path,
87
- suppress_warning=True,
88
- )
89
- if os.getenv(GIT_SSH_PRIVATE_KEY_VAR):
90
- private_key = os.getenv(GIT_SSH_PRIVATE_KEY_VAR)
88
+ private_key = get_settings_value(GIT_SSH_PRIVATE_KEY)
89
+ if not private_key:
90
+ private_key = get_secret_value(
91
+ pk_secret_name,
92
+ repo_name=repo_path,
93
+ suppress_warning=True,
94
+ )
91
95
  if private_key:
92
96
  with open(custom_private_key_file, 'w') as f:
93
97
  f.write(base64.b64decode(private_key).decode('utf-8'))
@@ -137,10 +141,8 @@ def add_host_to_known_hosts(remote_repo_link: str):
137
141
 
138
142
 
139
143
  def get_access_token(git_config, repo_path: str = None) -> str:
140
- token = None
141
- if os.getenv(GIT_ACCESS_TOKEN_VAR):
142
- token = os.getenv(GIT_ACCESS_TOKEN_VAR)
143
- elif git_config and git_config.access_token_secret_name:
144
+ token = get_settings_value(GIT_ACCESS_TOKEN)
145
+ if not token and git_config and git_config.access_token_secret_name:
144
146
  token = get_secret_value(
145
147
  git_config.access_token_secret_name,
146
148
  repo_name=repo_path or get_repo_path(),
@@ -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
@@ -1198,7 +1197,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
1198
1197
  f'Please run upstream blocks {upstream_block_uuids} '
1199
1198
  'before running the current block.'
1200
1199
  )
1201
- global_vars = self.__enrich_global_vars(
1200
+ global_vars = self.enrich_global_vars(
1202
1201
  global_vars,
1203
1202
  dynamic_block_index=dynamic_block_index,
1204
1203
  )
@@ -2161,6 +2160,9 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
2161
2160
  )
2162
2161
  pairs.append(tup)
2163
2162
 
2163
+ if len(pairs) > 10:
2164
+ # Limit the number of dynamic block children we display output for in the UI
2165
+ pairs = pairs[:DATAFRAME_SAMPLE_COUNT_PREVIEW]
2164
2166
  for pair in pairs:
2165
2167
  child_data = None
2166
2168
  metadata = None
@@ -2201,6 +2203,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
2201
2203
  self.pipeline.uuid,
2202
2204
  block_uuid,
2203
2205
  partition=execution_partition,
2206
+ max_results=DATAFRAME_SAMPLE_COUNT_PREVIEW,
2204
2207
  )
2205
2208
 
2206
2209
  if not include_print_outputs:
@@ -3034,7 +3037,7 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
3034
3037
  variable_mapping = merge_dict(output_variables, consolidated_print_variables)
3035
3038
  return variable_mapping
3036
3039
 
3037
- def __enrich_global_vars(
3040
+ def enrich_global_vars(
3038
3041
  self,
3039
3042
  global_vars: Dict = None,
3040
3043
  dynamic_block_index: int = None,
@@ -3655,23 +3658,29 @@ class AddonBlock(Block):
3655
3658
  global_vars['dynamic_block_index'] = dynamic_block_index
3656
3659
 
3657
3660
  if parent_block:
3661
+ if parent_block.global_vars is None:
3662
+ global_vars_copy = global_vars.copy()
3663
+ parent_block.enrich_global_vars(
3664
+ global_vars=global_vars_copy,
3665
+ dynamic_block_index=dynamic_block_index,
3666
+ )
3667
+ global_vars = merge_dict(parent_block.global_vars, global_vars)
3658
3668
  global_vars['parent_block_uuid'] = parent_block.uuid
3659
3669
 
3660
- if parent_block and \
3661
- parent_block.pipeline and \
3662
- PipelineType.INTEGRATION == parent_block.pipeline.type:
3663
-
3664
- template_runtime_configuration = parent_block.template_runtime_configuration
3665
- index = template_runtime_configuration.get('index', None)
3666
- is_last_block_run = template_runtime_configuration.get('is_last_block_run', False)
3667
- selected_streams = template_runtime_configuration.get('selected_streams', [])
3668
- stream = selected_streams[0] if len(selected_streams) >= 1 else None
3669
- destination_table = template_runtime_configuration.get('destination_table', stream)
3670
-
3671
- global_vars['index'] = index
3672
- global_vars['is_last_block_run'] = is_last_block_run
3673
- global_vars['stream'] = stream
3674
- global_vars['destination_table'] = destination_table
3670
+ if parent_block.pipeline and \
3671
+ PipelineType.INTEGRATION == parent_block.pipeline.type:
3672
+
3673
+ template_runtime_configuration = parent_block.template_runtime_configuration
3674
+ index = template_runtime_configuration.get('index', None)
3675
+ is_last_block_run = template_runtime_configuration.get('is_last_block_run', False)
3676
+ selected_streams = template_runtime_configuration.get('selected_streams', [])
3677
+ stream = selected_streams[0] if len(selected_streams) >= 1 else None
3678
+ destination_table = template_runtime_configuration.get('destination_table', stream)
3679
+
3680
+ global_vars['index'] = index
3681
+ global_vars['is_last_block_run'] = is_last_block_run
3682
+ global_vars['stream'] = stream
3683
+ global_vars['destination_table'] = destination_table
3675
3684
 
3676
3685
  return global_vars
3677
3686