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
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import os
2
3
  from datetime import datetime
3
4
  from unittest.mock import patch
4
5
 
@@ -20,15 +21,20 @@ class SessionOperationTests(BaseApiTestCase):
20
21
 
21
22
  operation = self.build_operation(
22
23
  action=constants.CREATE,
23
- payload=dict(session=dict(
24
- email=user.email,
25
- password=password,
26
- )),
24
+ payload=dict(
25
+ session=dict(
26
+ email=user.email,
27
+ password=password,
28
+ )
29
+ ),
27
30
  resource='sessions',
31
+ user=None,
28
32
  )
29
33
  response = await operation.execute()
30
34
 
31
- access_token = Oauth2AccessToken.query.filter(Oauth2AccessToken.user_id == user.id).first()
35
+ access_token = Oauth2AccessToken.query.filter(
36
+ Oauth2AccessToken.user_id == user.id
37
+ ).first()
32
38
 
33
39
  self.assertEqual(
34
40
  response['session']['token'],
@@ -41,22 +47,32 @@ class SessionOperationTests(BaseApiTestCase):
41
47
  user = create_user(password=password)
42
48
 
43
49
  with patch('mage_ai.api.policies.BasePolicy.DISABLE_NOTEBOOK_EDIT_ACCESS', 1):
44
- with patch('mage_ai.api.policies.BasePolicy.REQUIRE_USER_AUTHENTICATION', 1):
45
- with patch('mage_ai.api.policies.BasePolicy.REQUIRE_USER_PERMISSIONS', 0):
50
+ with patch(
51
+ 'mage_ai.api.policies.BasePolicy.REQUIRE_USER_AUTHENTICATION', 1
52
+ ):
53
+ with patch(
54
+ 'mage_ai.api.policies.BasePolicy.REQUIRE_USER_PERMISSIONS', 0
55
+ ):
46
56
  operation = self.build_operation(
47
57
  action=constants.CREATE,
48
- payload=dict(session=dict(
49
- email=user.email,
50
- password=password,
51
- )),
58
+ payload=dict(
59
+ session=dict(
60
+ email=user.email,
61
+ password=password,
62
+ )
63
+ ),
52
64
  resource='sessions',
53
65
  user=None,
54
66
  )
55
67
  response = await operation.execute()
56
68
 
57
- access_token = Oauth2AccessToken.query.filter(
58
- Oauth2AccessToken.user_id == user.id
59
- ).order_by(Oauth2AccessToken.created_at.desc()).first()
69
+ access_token = (
70
+ Oauth2AccessToken.query.filter(
71
+ Oauth2AccessToken.user_id == user.id
72
+ )
73
+ .order_by(Oauth2AccessToken.created_at.desc())
74
+ .first()
75
+ )
60
76
 
61
77
  self.assertEqual(
62
78
  response['session']['token'],
@@ -69,11 +85,14 @@ class SessionOperationTests(BaseApiTestCase):
69
85
 
70
86
  operation = self.build_operation(
71
87
  action=constants.CREATE,
72
- payload=dict(session=dict(
73
- email=user.email,
74
- password='not password',
75
- )),
88
+ payload=dict(
89
+ session=dict(
90
+ email=user.email,
91
+ password='not password',
92
+ )
93
+ ),
76
94
  resource='sessions',
95
+ user=None,
77
96
  )
78
97
  response = await operation.execute()
79
98
 
@@ -89,11 +108,14 @@ class SessionOperationTests(BaseApiTestCase):
89
108
  username = "novachrono"
90
109
  operation = self.build_operation(
91
110
  action=constants.CREATE,
92
- payload=dict(session=dict(
93
- email=username,
94
- password="Wizard King",
95
- )),
111
+ payload=dict(
112
+ session=dict(
113
+ email=username,
114
+ password="Wizard King",
115
+ )
116
+ ),
96
117
  resource='sessions',
118
+ user=None,
97
119
  )
98
120
  await operation.execute()
99
121
 
@@ -111,11 +133,14 @@ class SessionOperationTests(BaseApiTestCase):
111
133
  username = "licht"
112
134
  operation = self.build_operation(
113
135
  action=constants.CREATE,
114
- payload=dict(session=dict(
115
- email=username,
116
- password="Golden Dawn",
117
- )),
136
+ payload=dict(
137
+ session=dict(
138
+ email=username,
139
+ password="Golden Dawn",
140
+ )
141
+ ),
118
142
  resource='sessions',
143
+ user=None,
119
144
  )
120
145
  response = await operation.execute()
121
146
 
@@ -134,11 +159,14 @@ class SessionOperationTests(BaseApiTestCase):
134
159
  username = "yami"
135
160
  operation = self.build_operation(
136
161
  action=constants.CREATE,
137
- payload=dict(session=dict(
138
- email=username,
139
- password="black bull",
140
- )),
162
+ payload=dict(
163
+ session=dict(
164
+ email=username,
165
+ password="black bull",
166
+ )
167
+ ),
141
168
  resource='sessions',
169
+ user=None,
142
170
  )
143
171
  response = await operation.execute()
144
172
 
@@ -148,28 +176,35 @@ class SessionOperationTests(BaseApiTestCase):
148
176
  self.assertIsNotNone(response['error'])
149
177
 
150
178
  @patch('mage_ai.api.resources.SessionResource.AUTHENTICATION_MODE', 'ldap')
151
- @patch('mage_ai.authentication.ldap.LDAP_ROLES_MAPPING', json.dumps(dict(Admin=['Admin'])))
152
179
  @patch.object(LDAPConnection, 'authorize')
153
180
  @patch.object(LDAPConnection, 'authenticate')
154
181
  async def test_ldap_login_with_role_mapping(self, mock_authenticate, mock_authorize):
155
- mock_authenticate.return_value = (True, "Yami_Sukehiro", dict(memberOf=['Admin']))
182
+ mock_authenticate.return_value = (
183
+ True,
184
+ "Yami_Sukehiro",
185
+ dict(memberOf=['Admin']),
186
+ )
156
187
  mock_authorize.return_value = True
157
188
 
158
189
  Role.create_default_roles()
159
190
 
160
- username = self.faker.email()
161
- operation = self.build_operation(
162
- action=constants.CREATE,
163
- payload=dict(session=dict(
164
- email=username,
165
- password="black bull",
166
- )),
167
- resource='sessions',
168
- )
169
- await operation.execute()
170
-
171
- mock_authenticate.assert_called_once_with(username, "black bull")
172
- mock_authorize.assert_called_once_with("Yami_Sukehiro")
173
- user = User.query.filter(User.username == username).first()
174
- self.assertIsNotNone(user)
175
- self.assertEqual(user.roles_new[0].name, 'Admin')
191
+ with patch.dict(os.environ, dict(LDAP_ROLES_MAPPING=json.dumps(dict(Admin=['Admin'])))):
192
+ username = self.faker.email()
193
+ operation = self.build_operation(
194
+ action=constants.CREATE,
195
+ payload=dict(
196
+ session=dict(
197
+ email=username,
198
+ password="black bull",
199
+ )
200
+ ),
201
+ resource='sessions',
202
+ user=None,
203
+ )
204
+ await operation.execute()
205
+
206
+ mock_authenticate.assert_called_once_with(username, "black bull")
207
+ mock_authorize.assert_called_once_with("Yami_Sukehiro")
208
+ user = User.query.filter(User.username == username).first()
209
+ self.assertIsNotNone(user)
210
+ self.assertEqual(user.roles_new[0].name, 'Admin')
@@ -1,14 +1,19 @@
1
1
  import asyncio
2
2
  from datetime import datetime, timedelta
3
3
  from unittest.mock import MagicMock, patch
4
+ from uuid import uuid4
4
5
 
5
6
  from freezegun import freeze_time
6
7
 
7
8
  from mage_ai.authentication.oauth.constants import ProviderName
8
- from mage_ai.authentication.oauth.utils import refresh_token_for_client
9
+ from mage_ai.authentication.oauth.utils import (
10
+ access_tokens_for_client,
11
+ refresh_token_for_client,
12
+ )
9
13
  from mage_ai.data_preparation.git.api import get_oauth_client_id
10
14
  from mage_ai.orchestration.db.models.oauth import Oauth2AccessToken, Oauth2Application
11
15
  from mage_ai.tests.base_test import AsyncDBTestCase
16
+ from mage_ai.tests.factory import create_user
12
17
 
13
18
 
14
19
  class OauthUtilsTest(AsyncDBTestCase):
@@ -17,11 +22,54 @@ class OauthUtilsTest(AsyncDBTestCase):
17
22
  super().setUpClass()
18
23
  self.provider = ProviderName.GITLAB
19
24
  self.client_id = get_oauth_client_id(self.provider)
25
+
26
+ def setUp(self):
20
27
  self.oauth_application = Oauth2Application.create(
21
28
  client_id=self.client_id,
22
29
  client_type=Oauth2Application.ClientType.PRIVATE,
23
30
  name=self.provider,
24
31
  )
32
+ self.user = create_user()
33
+
34
+ def tearDown(self):
35
+ Oauth2Application.query.delete()
36
+ Oauth2AccessToken.query.delete()
37
+
38
+ super().tearDown()
39
+
40
+ def test_access_tokens_for_client(self):
41
+ token = Oauth2AccessToken.create(
42
+ expires=datetime.utcnow() + timedelta(days=1),
43
+ token=uuid4().hex,
44
+ oauth2_application_id=self.oauth_application.id,
45
+ )
46
+
47
+ tokens = access_tokens_for_client(self.client_id)
48
+
49
+ self.assertEqual(len(tokens), 1)
50
+ self.assertEqual(tokens[0].token, token.token)
51
+
52
+ def test_access_tokens_for_client_with_user(self):
53
+ Oauth2AccessToken.create(
54
+ expires=datetime.utcnow() + timedelta(days=1),
55
+ token=uuid4().hex,
56
+ oauth2_application_id=self.oauth_application.id,
57
+ )
58
+
59
+ self.assertEqual(
60
+ len(access_tokens_for_client(self.client_id, user=self.user)), 0
61
+ )
62
+ self.assertEqual(len(access_tokens_for_client(self.client_id)), 1)
63
+
64
+ token = Oauth2AccessToken.create(
65
+ expires=datetime.utcnow() + timedelta(days=1),
66
+ token=uuid4().hex,
67
+ oauth2_application_id=self.oauth_application.id,
68
+ user_id=self.user.id,
69
+ )
70
+ tokens = access_tokens_for_client(self.client_id, user=self.user)
71
+ self.assertEqual(len(tokens), 1)
72
+ self.assertEqual(tokens[0].token, token.token)
25
73
 
26
74
  @freeze_time('2024-02-06 04:00:00')
27
75
  @patch(
@@ -43,11 +91,13 @@ class OauthUtilsTest(AsyncDBTestCase):
43
91
  provider_instance.provider = self.provider
44
92
 
45
93
  future = asyncio.Future()
46
- future.set_result({
47
- 'access_token': 'new',
48
- 'refresh_token': 'new_refresh',
49
- 'expires_in': 3600,
50
- })
94
+ future.set_result(
95
+ {
96
+ 'access_token': 'new',
97
+ 'refresh_token': 'new_refresh',
98
+ 'expires_in': 3600,
99
+ }
100
+ )
51
101
  provider_instance.get_refresh_token_response.return_value = future
52
102
  new_token = await refresh_token_for_client(self.client_id, provider_instance)
53
103
 
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import os
2
3
  import unittest
3
4
  from unittest.mock import AsyncMock, Mock, patch
4
5
 
@@ -6,18 +7,6 @@ from mage_ai.authentication.providers.active_directory import ADProvider
6
7
 
7
8
 
8
9
  class ADProviderTest(unittest.IsolatedAsyncioTestCase):
9
- @patch(
10
- 'mage_ai.authentication.providers.active_directory.ACTIVE_DIRECTORY_DIRECTORY_ID',
11
- 'test_directory_id',
12
- )
13
- @patch(
14
- 'mage_ai.authentication.providers.active_directory.ACTIVE_DIRECTORY_CLIENT_ID',
15
- 'test_client_id',
16
- )
17
- @patch(
18
- 'mage_ai.authentication.providers.active_directory.ACTIVE_DIRECTORY_CLIENT_SECRET',
19
- 'test_client_secret',
20
- )
21
10
  @patch('aiohttp.ClientSession')
22
11
  async def test_map_ad_roles_to_mage_roles(self, mock_client_session):
23
12
  roles_mapping = json.dumps(
@@ -27,9 +16,14 @@ class ADProviderTest(unittest.IsolatedAsyncioTestCase):
27
16
  }
28
17
  )
29
18
 
30
- with patch(
31
- 'mage_ai.authentication.providers.active_directory.ACTIVE_DIRECTORY_ROLES_MAPPING',
32
- roles_mapping,
19
+ with patch.dict(
20
+ os.environ,
21
+ dict(
22
+ ACTIVE_DIRECTORY_DIRECTORY_ID='test_directory_id',
23
+ ACTIVE_DIRECTORY_CLIENT_ID='test_client_id',
24
+ ACTIVE_DIRECTORY_CLIENT_SECRET='test_client_secret',
25
+ ACTIVE_DIRECTORY_ROLES_MAPPING=roles_mapping,
26
+ ),
33
27
  ):
34
28
 
35
29
  def side_effect(*args, **kwargs):
@@ -7,14 +7,17 @@ from faker import Faker
7
7
  from pandas.testing import assert_frame_equal
8
8
 
9
9
  # from mage_ai.data_cleaner.column_types.constants import ColumnType
10
- from mage_ai.data_preparation.models.block import Block, BlockType
10
+ from mage_ai.data_preparation.models.block import Block, BlockType, CallbackBlock
11
11
  from mage_ai.data_preparation.models.block.errors import HasDownstreamDependencies
12
12
  from mage_ai.data_preparation.models.pipeline import Pipeline
13
13
  from mage_ai.data_preparation.repo_manager import get_repo_config
14
14
  from mage_ai.data_preparation.variable_manager import VariableManager
15
15
  from mage_ai.shared.path_fixer import add_root_repo_path_to_relative_path
16
16
  from mage_ai.tests.base_test import DBTestCase
17
- from mage_ai.tests.factory import create_integration_pipeline_with_blocks
17
+ from mage_ai.tests.factory import (
18
+ create_integration_pipeline_with_blocks,
19
+ create_pipeline,
20
+ )
18
21
  from mage_ai.tests.shared.mixins import ProjectPlatformMixin
19
22
 
20
23
 
@@ -763,3 +766,37 @@ class BlockProjectPlatformTests(ProjectPlatformMixin):
763
766
  )
764
767
 
765
768
  self.assertEqual(block.file_path, add_root_repo_path_to_relative_path(path))
769
+
770
+
771
+ class CallbackBlockTest(DBTestCase):
772
+ def setUp(self):
773
+ self.pipeline = create_pipeline('callback_pipeline', self.repo_path)
774
+
775
+ def tearDown(self):
776
+ self.pipeline.delete()
777
+
778
+ def test_create_global_vars_from_parent_block(self):
779
+ parent_block = Block.create(
780
+ 'test_data_loader',
781
+ 'data_loader',
782
+ self.repo_path,
783
+ pipeline=self.pipeline,
784
+ )
785
+ callback_block = CallbackBlock.create(parent_block.name)
786
+ self.pipeline.add_block(callback_block)
787
+ parent_block = parent_block.update(
788
+ dict(callback_blocks=[callback_block.uuid])
789
+ )
790
+ parent_block.global_vars = dict(
791
+ configuration=dict(table_name='load_data_table')
792
+ )
793
+
794
+ global_vars = dict(
795
+ random_var=1,
796
+ )
797
+ new_vars = callback_block._create_global_vars(
798
+ global_vars,
799
+ parent_block=parent_block,
800
+ )
801
+
802
+ self.assertIsNotNone(new_vars.get('configuration'))
@@ -1,5 +1,5 @@
1
1
  import os
2
- from datetime import datetime, timezone
2
+ from datetime import datetime, timedelta, timezone
3
3
  from unittest.mock import Mock, patch
4
4
  from uuid import uuid4
5
5
 
@@ -1677,6 +1677,38 @@ class PipelineRunTests(DBTestCase):
1677
1677
  set([pipeline_run2.id, pipeline_run4.id]),
1678
1678
  )
1679
1679
 
1680
+ @freeze_time('2023-10-11 12:13:14')
1681
+ def test_get_variables_intervals_for_cron(self):
1682
+ pipeline_schedule = PipelineSchedule.create(
1683
+ name=self.faker.unique.name(),
1684
+ pipeline_uuid=self.pipeline.uuid,
1685
+ schedule_interval='*/10 * * * *',
1686
+ schedule_type=ScheduleType.TIME,
1687
+ )
1688
+
1689
+ pipeline_run = PipelineRun.create(
1690
+ pipeline_uuid=self.pipeline.uuid,
1691
+ pipeline_schedule_id=pipeline_schedule.id,
1692
+ create_block_runs=False,
1693
+ execution_date=pipeline_schedule.current_execution_date(),
1694
+ )
1695
+
1696
+ variables = pipeline_run.get_variables(pipeline_uuid=pipeline_run.pipeline_uuid)
1697
+
1698
+ self.assertEqual(
1699
+ datetime(2023, 10, 11, 12, 20, 0) - variables['interval_end_datetime'],
1700
+ timedelta(0),
1701
+ )
1702
+ self.assertEqual(600, variables['interval_seconds'])
1703
+ self.assertEqual(
1704
+ datetime(2023, 10, 11, 12, 10, 0) - variables['interval_start_datetime'],
1705
+ timedelta(0),
1706
+ )
1707
+ self.assertEqual(
1708
+ datetime(2023, 10, 11, 12, 0, 0) - variables['interval_start_datetime_previous'],
1709
+ timedelta(0),
1710
+ )
1711
+
1680
1712
 
1681
1713
  class BlockRunTests(DBTestCase):
1682
1714
  @classmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mage-ai
3
- Version: 0.9.65
3
+ Version: 0.9.67
4
4
  Summary: Mage is a tool for building and deploying data pipelines.
5
5
  Home-page: https://github.com/mage-ai/mage-ai
6
6
  Author: Mage
@@ -58,6 +58,7 @@ Requires-Dist: thefuzz[speedup] ==0.19.0
58
58
  Requires-Dist: tornado ==6.3.3
59
59
  Requires-Dist: typer[all] ==0.9.0
60
60
  Requires-Dist: typing-extensions ==4.5.0
61
+ Requires-Dist: watchdog ==4.0.0
61
62
  Provides-Extra: ai
62
63
  Requires-Dist: astor >=0.8.1 ; extra == 'ai'
63
64
  Requires-Dist: langchain >=0.0.222 ; extra == 'ai'