mage-ai 0.9.73__py3-none-any.whl → 0.9.74__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. mage_ai/ai/constants.py +2 -2
  2. mage_ai/ai/llm_pipeline_wizard.py +5 -3
  3. mage_ai/ai/openai_client.py +11 -0
  4. mage_ai/api/constants.py +4 -5
  5. mage_ai/api/oauth_scope.py +2 -2
  6. mage_ai/api/operations/constants.py +2 -2
  7. mage_ai/api/presenters/SyncPresenter.py +4 -1
  8. mage_ai/authentication/oauth/constants.py +2 -2
  9. mage_ai/authentication/operation_history/constants.py +2 -2
  10. mage_ai/authentication/permissions/constants.py +5 -6
  11. mage_ai/cache/constants.py +2 -2
  12. mage_ai/cache/dbt/constants.py +2 -3
  13. mage_ai/cluster_manager/constants.py +2 -2
  14. mage_ai/cluster_manager/kubernetes/workload_manager.py +3 -2
  15. mage_ai/command_center/constants.py +13 -13
  16. mage_ai/data_cleaner/column_types/constants.py +2 -2
  17. mage_ai/data_cleaner/transformer_actions/column.py +19 -7
  18. mage_ai/data_cleaner/transformer_actions/constants.py +10 -9
  19. mage_ai/data_integrations/sources/constants.py +2 -0
  20. mage_ai/data_preparation/git/utils.py +4 -1
  21. mage_ai/data_preparation/logging/__init__.py +2 -2
  22. mage_ai/data_preparation/logging/logger.py +3 -3
  23. mage_ai/data_preparation/models/block/__init__.py +9 -3
  24. mage_ai/data_preparation/models/block/data_integration/constants.py +2 -2
  25. mage_ai/data_preparation/models/block/dbt/constants.py +3 -3
  26. mage_ai/data_preparation/models/block/dynamic/factory.py +40 -3
  27. mage_ai/data_preparation/models/block/dynamic/utils.py +31 -33
  28. mage_ai/data_preparation/models/block/dynamic/variables.py +1 -1
  29. mage_ai/data_preparation/models/block/settings/dynamic/constants.py +3 -3
  30. mage_ai/data_preparation/models/block/settings/dynamic/mixins.py +63 -4
  31. mage_ai/data_preparation/models/block/settings/global_data_products/models.py +2 -2
  32. mage_ai/data_preparation/models/constants.py +10 -10
  33. mage_ai/data_preparation/models/global_hooks/constants.py +7 -8
  34. mage_ai/data_preparation/models/global_hooks/models.py +5 -5
  35. mage_ai/data_preparation/models/project/constants.py +2 -2
  36. mage_ai/data_preparation/models/triggers/__init__.py +6 -4
  37. mage_ai/data_preparation/models/variables/constants.py +5 -5
  38. mage_ai/data_preparation/models/widget/constants.py +5 -5
  39. mage_ai/data_preparation/preferences.py +9 -16
  40. mage_ai/data_preparation/repo_manager.py +2 -2
  41. mage_ai/data_preparation/sync/__init__.py +2 -2
  42. mage_ai/data_preparation/templates/data_exporters/streaming/generic_python.py +1 -1
  43. mage_ai/data_preparation/templates/data_loaders/streaming/nats.yaml +3 -0
  44. mage_ai/errors/constants.py +2 -2
  45. mage_ai/io/base.py +28 -15
  46. mage_ai/io/config.py +3 -3
  47. mage_ai/io/export_utils.py +2 -2
  48. mage_ai/io/google_cloud_storage.py +3 -2
  49. mage_ai/io/io_config.py +3 -2
  50. mage_ai/io/postgres.py +2 -1
  51. mage_ai/kernels/magic/constants.py +4 -4
  52. mage_ai/orchestration/constants.py +2 -2
  53. mage_ai/orchestration/db/constants.py +2 -2
  54. mage_ai/orchestration/db/models/oauth.py +5 -5
  55. mage_ai/orchestration/db/models/schedules.py +28 -8
  56. mage_ai/orchestration/db/models/schedules_project_platform.py +10 -8
  57. mage_ai/orchestration/job_manager.py +2 -2
  58. mage_ai/orchestration/monitor/monitor_stats.py +2 -2
  59. mage_ai/orchestration/notification/config.py +2 -2
  60. mage_ai/orchestration/pipeline_scheduler_original.py +4 -12
  61. mage_ai/orchestration/queue/config.py +2 -2
  62. mage_ai/orchestration/queue/process_queue.py +3 -3
  63. mage_ai/presenters/charts/data_sources/constants.py +2 -2
  64. mage_ai/presenters/interactions/constants.py +4 -4
  65. mage_ai/presenters/pages/models/constants.py +4 -4
  66. mage_ai/server/constants.py +1 -1
  67. mage_ai/server/frontend_dist/404.html +2 -2
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-663c909dcda4c23a.js → _app-5bdff745074fb350.js} +2 -2
  69. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-43534cc51fce8644.js → webpack-b9a067f3bd0a3a05.js} +1 -1
  70. mage_ai/server/frontend_dist/block-layout.html +2 -2
  71. mage_ai/server/frontend_dist/compute.html +2 -2
  72. mage_ai/server/frontend_dist/files.html +2 -2
  73. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  74. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  75. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  76. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  77. mage_ai/server/frontend_dist/index.html +2 -2
  78. mage_ai/server/frontend_dist/manage/files.html +2 -2
  79. mage_ai/server/frontend_dist/manage/overview.html +2 -2
  80. mage_ai/server/frontend_dist/manage/pipeline-runs.html +2 -2
  81. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  82. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  83. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  84. mage_ai/server/frontend_dist/manage/users.html +2 -2
  85. mage_ai/server/frontend_dist/manage.html +2 -2
  86. mage_ai/server/frontend_dist/oauth.html +3 -3
  87. mage_ai/server/frontend_dist/overview.html +2 -2
  88. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  89. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  90. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  91. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  92. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  93. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  94. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  95. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  96. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  97. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  98. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  99. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  100. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  101. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  102. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  103. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  104. mage_ai/server/frontend_dist/pipelines.html +2 -2
  105. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  106. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  107. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  108. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  109. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  110. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  111. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  112. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  113. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  114. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  115. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  116. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  117. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  118. mage_ai/server/frontend_dist/settings.html +2 -2
  119. mage_ai/server/frontend_dist/sign-in.html +5 -5
  120. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  121. mage_ai/server/frontend_dist/templates.html +2 -2
  122. mage_ai/server/frontend_dist/terminal.html +2 -2
  123. mage_ai/server/frontend_dist/test.html +2 -2
  124. mage_ai/server/frontend_dist/triggers.html +2 -2
  125. mage_ai/server/frontend_dist/v2/canvas.html +2 -2
  126. mage_ai/server/frontend_dist/v2.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/pages/{_app-bb4a0e0d783622a8.js → _app-90de19bc03f1484b.js} +2 -2
  130. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-9eb1dd2ee735aaac.js → webpack-12ad70eb5c31aa92.js} +1 -1
  131. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  132. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  133. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  134. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  135. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  136. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  137. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  138. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  139. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  140. mage_ai/server/frontend_dist_base_path_template/manage/overview.html +2 -2
  141. mage_ai/server/frontend_dist_base_path_template/manage/pipeline-runs.html +2 -2
  142. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  143. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  144. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  145. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  146. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  147. mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
  148. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  149. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  150. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  151. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  152. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  153. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  154. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  155. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  156. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  157. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  158. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  159. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  160. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  161. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  162. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  163. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  164. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  165. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  166. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  167. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  168. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  169. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  172. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  173. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
  181. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  183. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/v2/canvas.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/v2.html +2 -2
  188. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  189. mage_ai/server/kernel_output_parser.py +2 -3
  190. mage_ai/server/kernels.py +2 -3
  191. mage_ai/server/scheduler_manager.py +2 -2
  192. mage_ai/server/server.py +12 -0
  193. mage_ai/server/websockets/constants.py +4 -4
  194. mage_ai/services/compute/aws/constants.py +2 -2
  195. mage_ai/services/compute/aws/steps.py +16 -10
  196. mage_ai/services/compute/constants.py +4 -4
  197. mage_ai/services/compute/models.py +4 -4
  198. mage_ai/services/k8s/config.py +4 -0
  199. mage_ai/services/k8s/job_manager.py +2 -0
  200. mage_ai/services/spark/constants.py +3 -3
  201. mage_ai/services/spark/models/jobs.py +2 -2
  202. mage_ai/services/spark/models/sqls.py +2 -2
  203. mage_ai/services/spark/models/stages.py +4 -4
  204. mage_ai/services/spark/models/threads.py +2 -2
  205. mage_ai/settings/backends.py +3 -2
  206. mage_ai/settings/models/configuration_option.py +3 -3
  207. mage_ai/settings/server.py +5 -0
  208. mage_ai/shared/constants.py +3 -3
  209. mage_ai/shared/custom_logger.py +13 -13
  210. mage_ai/shared/enum.py +11 -0
  211. mage_ai/shared/environments.py +1 -1
  212. mage_ai/shared/logger.py +2 -2
  213. mage_ai/shared/models.py +2 -1
  214. mage_ai/streaming/constants.py +3 -3
  215. mage_ai/streaming/sinks/kafka.py +2 -2
  216. mage_ai/streaming/sinks/postgres.py +6 -0
  217. mage_ai/streaming/sources/amazon_sqs.py +2 -2
  218. mage_ai/streaming/sources/base.py +2 -2
  219. mage_ai/streaming/sources/kafka.py +20 -4
  220. mage_ai/streaming/sources/nats_js.py +10 -3
  221. mage_ai/streaming/sources/shared.py +3 -2
  222. mage_ai/system/constants.py +2 -2
  223. mage_ai/tests/api/policies/permissions/test_base_policy_with_permissions.py +2 -2
  224. mage_ai/tests/data_cleaner/transformer_actions/test_trim_transformer.py +161 -0
  225. mage_ai/tests/data_preparation/models/block/dbt/test_profiles.py +1 -1
  226. mage_ai/tests/data_preparation/models/block/dynamic/test_combos.py +1 -1
  227. mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +3 -2
  228. mage_ai/tests/data_preparation/models/test_blocks_helper.py +1 -1
  229. mage_ai/tests/data_preparation/models/variables/test_summarizer.py +1 -1
  230. mage_ai/tests/data_preparation/sync/test_git_sync.py +6 -6
  231. mage_ai/tests/orchestration/queue/test_process_queue.py +3 -2
  232. mage_ai/tests/orchestration/test_pipeline_scheduler.py +1 -0
  233. mage_ai/tests/settings/test_platform.py +2 -2
  234. mage_ai/tests/streaming/sinks/test_generic_io.py +25 -21
  235. mage_ai/usage_statistics/constants.py +4 -4
  236. {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/METADATA +172 -171
  237. {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/RECORD +247 -245
  238. {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/WHEEL +1 -1
  239. /mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-663c909dcda4c23a.js.LICENSE.txt → _app-5bdff745074fb350.js.LICENSE.txt} +0 -0
  240. /mage_ai/server/frontend_dist/_next/static/{kxGpiudO3f9aX6FAiqydf → pLWT6Sqd09xYpufCVIqnz}/_buildManifest.js +0 -0
  241. /mage_ai/server/frontend_dist/_next/static/{kxGpiudO3f9aX6FAiqydf → pLWT6Sqd09xYpufCVIqnz}/_ssgManifest.js +0 -0
  242. /mage_ai/server/frontend_dist_base_path_template/_next/static/{H5pcGxWf1BkhXDRs2BqiI → JQewSAObpbhO0wrdAM6Ng}/_buildManifest.js +0 -0
  243. /mage_ai/server/frontend_dist_base_path_template/_next/static/{H5pcGxWf1BkhXDRs2BqiI → JQewSAObpbhO0wrdAM6Ng}/_ssgManifest.js +0 -0
  244. /mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-bb4a0e0d783622a8.js.LICENSE.txt → _app-90de19bc03f1484b.js.LICENSE.txt} +0 -0
  245. {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/LICENSE +0 -0
  246. {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/entry_points.txt +0 -0
  247. {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,161 @@
1
+ import unittest
2
+
3
+ import pandas as pd
4
+
5
+ from mage_ai.data_cleaner.transformer_actions.base import BaseAction
6
+ from mage_ai.data_cleaner.transformer_actions.constants import ActionType, Axis
7
+ from mage_ai.data_cleaner.transformer_actions.utils import build_transformer_action
8
+
9
+
10
+ class TestTrimTransformer(unittest.TestCase):
11
+ def test_basic_trimming(self):
12
+ df = pd.DataFrame({
13
+ 'category': [' A ', ' B ', ' C ', ' D ']
14
+ })
15
+
16
+ expected_output = pd.DataFrame({
17
+ 'category': ['A', 'B', 'C', 'D']
18
+ })
19
+
20
+ action = build_transformer_action(
21
+ df,
22
+ action_type=ActionType.REFORMAT,
23
+ arguments=['category'],
24
+ axis=Axis.COLUMN,
25
+ options={'reformat': 'trim'}
26
+ )
27
+
28
+ output = BaseAction(action).execute(df)
29
+
30
+ pd.testing.assert_frame_equal(output, expected_output)
31
+ print("Test 1 (Basic Trimming): Passed")
32
+
33
+ def test_no_trimming_needed(self):
34
+ df = pd.DataFrame({
35
+ 'category': ['A', 'B', 'C', 'D']
36
+ })
37
+
38
+ expected_output = df.copy()
39
+
40
+ action = build_transformer_action(
41
+ df,
42
+ action_type=ActionType.REFORMAT,
43
+ arguments=['category'],
44
+ axis=Axis.COLUMN,
45
+ options={'reformat': 'trim'}
46
+ )
47
+
48
+ output = BaseAction(action).execute(df)
49
+
50
+ pd.testing.assert_frame_equal(output, expected_output)
51
+ print("Test 2 (No Trimming Needed): Passed")
52
+
53
+ def test_mixed_content(self):
54
+ df = pd.DataFrame({
55
+ 'category': [' A ', 'B', ' C', 'D ']
56
+ })
57
+
58
+ expected_output = pd.DataFrame({
59
+ 'category': ['A', 'B', 'C', 'D']
60
+ })
61
+
62
+ action = build_transformer_action(
63
+ df,
64
+ action_type=ActionType.REFORMAT,
65
+ arguments=['category'],
66
+ axis=Axis.COLUMN,
67
+ options={'reformat': 'trim'}
68
+ )
69
+
70
+ output = BaseAction(action).execute(df)
71
+
72
+ pd.testing.assert_frame_equal(output, expected_output)
73
+ print("Test 3 (Mixed Content): Passed")
74
+
75
+ def test_multiple_columns(self):
76
+ df = pd.DataFrame({
77
+ 'category': [' A ', ' B ', ' C ', ' D '],
78
+ 'subcategory': [' X ', 'Y ', ' Z', ' W ']
79
+ })
80
+
81
+ expected_output = pd.DataFrame({
82
+ 'category': ['A', 'B', 'C', 'D'],
83
+ 'subcategory': ['X', 'Y', 'Z', 'W']
84
+ })
85
+
86
+ action = build_transformer_action(
87
+ df,
88
+ action_type=ActionType.REFORMAT,
89
+ arguments=['category', 'subcategory'],
90
+ axis=Axis.COLUMN,
91
+ options={'reformat': 'trim'}
92
+ )
93
+
94
+ output = BaseAction(action).execute(df)
95
+
96
+ pd.testing.assert_frame_equal(output, expected_output)
97
+ print("Test 4 (Multiple Columns): Passed")
98
+
99
+ def test_empty_strings(self):
100
+ df = pd.DataFrame({
101
+ 'category': [' ', ' B ', ' ', ' D ']
102
+ })
103
+
104
+ expected_output = pd.DataFrame({
105
+ 'category': ['', 'B', '', 'D']
106
+ })
107
+
108
+ action = build_transformer_action(
109
+ df,
110
+ action_type=ActionType.REFORMAT,
111
+ arguments=['category'],
112
+ axis=Axis.COLUMN,
113
+ options={'reformat': 'trim'}
114
+ )
115
+
116
+ output = BaseAction(action).execute(df)
117
+
118
+ pd.testing.assert_frame_equal(output, expected_output)
119
+ print("Test 5 (Empty Strings): Passed")
120
+
121
+ def test_no_columns_to_trim(self):
122
+ df = pd.DataFrame({
123
+ 'category': [' A ', ' B ', ' C ', ' D ']
124
+ })
125
+
126
+ expected_output = df.copy()
127
+
128
+ action = build_transformer_action(
129
+ df,
130
+ action_type=ActionType.REFORMAT,
131
+ arguments=[],
132
+ axis=Axis.COLUMN,
133
+ options={'reformat': 'trim'}
134
+ )
135
+
136
+ output = BaseAction(action).execute(df)
137
+
138
+ pd.testing.assert_frame_equal(output, expected_output)
139
+ print("Test 6 (No Columns to Trim): Passed")
140
+
141
+ def test_column_not_found(self):
142
+ df = pd.DataFrame({
143
+ 'category': [' A ', ' B ', ' C ', ' D ']
144
+ })
145
+
146
+ with self.assertRaises(KeyError):
147
+ action = build_transformer_action(
148
+ df,
149
+ action_type=ActionType.REFORMAT,
150
+ arguments=['nonexistent_column'],
151
+ axis=Axis.COLUMN,
152
+ options={'reformat': 'trim'}
153
+ )
154
+
155
+ BaseAction(action).execute(df)
156
+
157
+ print("Test 7 (Column Not Found): Passed")
158
+
159
+
160
+ if __name__ == '__main__':
161
+ unittest.main()
@@ -85,7 +85,7 @@ target: dev
85
85
  lambda: MockUUID(),
86
86
  ):
87
87
  with Profiles(self.repo_path, self.variables) as profiles:
88
- self.assertNotEquals(
88
+ self.assertNotEqual(
89
89
  profiles.profiles_dir,
90
90
  self.repo_path
91
91
  )
@@ -110,7 +110,7 @@ class DynamicBlockCombinationTest(BaseApiTestCase):
110
110
  content = inspect.getsource(func)
111
111
 
112
112
  if content:
113
- block.update_content(f'@{block.type}\n{content}')
113
+ block.update_content(block.get_typed_content(content))
114
114
 
115
115
  return block
116
116
 
@@ -5,6 +5,7 @@ from faker import Faker
5
5
  from mage_ai.data_preparation.models.block.hook.block import HookBlock
6
6
  from mage_ai.data_preparation.models.constants import BlockType
7
7
  from mage_ai.data_preparation.models.global_hooks.models import HookStatus, HookStrategy
8
+ from mage_ai.shared.constants import ENV_TEST
8
9
  from mage_ai.tests.api.operations.test_base import BaseApiTestCase
9
10
  from mage_ai.tests.factory import create_pipeline_with_blocks
10
11
  from mage_ai.tests.shared.mixins import build_hooks
@@ -45,7 +46,7 @@ class HookBlockTest(BaseApiTestCase):
45
46
  check_status=True,
46
47
  configuration={},
47
48
  context={},
48
- env='test',
49
+ env=ENV_TEST,
49
50
  error_on_failure=True,
50
51
  mage=1,
51
52
  pipeline_uuid='',
@@ -84,7 +85,7 @@ class HookBlockTest(BaseApiTestCase):
84
85
  check_status=True,
85
86
  configuration={},
86
87
  context={},
87
- env='test',
88
+ env=ENV_TEST,
88
89
  error_on_failure=True,
89
90
  mage=1,
90
91
  pipeline_uuid='',
@@ -107,7 +107,7 @@ class BlockHelperTest(BaseApiTestCase):
107
107
  '\n'.join([
108
108
  'from mage_ai.data.models.generator import DataGenerator',
109
109
  'from mage_ai.data.tabular.mocks import create_dataframe',
110
- f'@{block.type}\n{content}',
110
+ block.get_typed_content(content),
111
111
  ])
112
112
  )
113
113
 
@@ -110,7 +110,7 @@ class VariableSummarizerTest(BaseApiTestCase):
110
110
  '\n'.join([
111
111
  'from mage_ai.data.models.generator import DataGenerator',
112
112
  'from mage_ai.data.tabular.mocks import create_dataframe',
113
- f'@{block.type}\n{content}',
113
+ block.get_typed_content(content),
114
114
  ])
115
115
  )
116
116
 
@@ -22,8 +22,8 @@ class GitSyncTest(DBTestCase):
22
22
 
23
23
  git_sync.sync_data()
24
24
 
25
- git_manager_instance_mock.reset_hard.called_once_with(branch='dev')
26
- git_manager_instance_mock.submodules_update.not_called()
25
+ git_manager_instance_mock.reset_hard.assert_called_once_with(branch='dev')
26
+ git_manager_instance_mock.submodules_update.assert_not_called()
27
27
 
28
28
  with open(os.path.join(self.repo_path, '.preferences.yaml'), 'r') as f:
29
29
  preferences = yaml.safe_load(f)
@@ -42,8 +42,8 @@ class GitSyncTest(DBTestCase):
42
42
 
43
43
  git_sync.sync_data()
44
44
 
45
- git_manager_instance_mock.reset_hard.called_once_with(branch='dev')
46
- git_manager_instance_mock.submodules_update.called_once()
45
+ git_manager_instance_mock.reset_hard.assert_called_once_with(branch='dev')
46
+ git_manager_instance_mock.submodules_update.assert_called_once()
47
47
 
48
48
  with open(os.path.join(self.repo_path, '.preferences.yaml'), 'r') as f:
49
49
  preferences = yaml.safe_load(f)
@@ -63,7 +63,7 @@ class GitSyncTest(DBTestCase):
63
63
 
64
64
  git_sync.sync_data()
65
65
 
66
- git_manager_instance_mock.reset_hard.called_once_with(branch='dev')
66
+ git_manager_instance_mock.reset_hard.assert_called_once_with(branch='dev')
67
67
 
68
68
  self.assertFalse(os.path.exists(preferences_file_path))
69
69
 
@@ -77,4 +77,4 @@ class GitSyncTest(DBTestCase):
77
77
 
78
78
  git_sync.reset()
79
79
 
80
- git_manager_instance_mock.clone.called_once_with(sync_submodules=False)
80
+ git_manager_instance_mock.clone.assert_called_once_with(sync_submodules=False)
@@ -33,9 +33,10 @@ class ProcessQueueTests(TestCase):
33
33
  self.assertFalse('block_run_3' in self.queue.job_dict)
34
34
  self.assertFalse('block_run_4' in self.queue.job_dict)
35
35
 
36
- @patch('mage_ai.orchestration.queue.process_queue.poll_job_and_execute')
36
+ @patch.object(ProcessQueue, 'start_worker_pool')
37
37
  @patch('mage_ai.orchestration.queue.process_queue.psutil.pid_exists')
38
- def test_has_job(self, mock_pid_exists, mock_poll_job_and_execute):
38
+ def test_has_job(self, mock_pid_exists, mock_start_worker_pool):
39
+ mock_start_worker_pool.return_value = None
39
40
  mock_pid_exists.return_value = True
40
41
 
41
42
  self.queue.job_dict['block_run_1'] = JobStatus.QUEUED
@@ -441,6 +441,7 @@ class PipelineSchedulerTests(DBTestCase):
441
441
  execution_partition=f'{pipeline_run.pipeline_schedule_id}',
442
442
  event={},
443
443
  pipeline_run_id=pipeline_run.id,
444
+ trigger_name='test_pipeline_2_trigger'
444
445
  ),
445
446
  dict(
446
447
  pipeline_run_id=pipeline_run.id,
@@ -205,12 +205,12 @@ class PlatformSettingsTest(ProjectPlatformMixin):
205
205
  ))
206
206
 
207
207
  def test_platform_settings_full_path(self):
208
- self.assertEquals(
208
+ self.assertEqual(
209
209
  platform_settings_full_path(), os.path.join(base_repo_path(), 'settings.yaml'),
210
210
  )
211
211
 
212
212
  def test_local_platform_settings_full_path(self):
213
- self.assertEquals(
213
+ self.assertEqual(
214
214
  local_platform_settings_full_path(), os.path.join(base_repo_path(), '.settings.yaml'),
215
215
  )
216
216
 
@@ -1,4 +1,4 @@
1
- import os
1
+ from pathlib import Path
2
2
  from unittest.mock import ANY, MagicMock, call, patch
3
3
 
4
4
  import pandas as pd
@@ -52,33 +52,40 @@ TEST_DATABASES = [
52
52
 
53
53
 
54
54
  class GenericIOTests(TestCase):
55
- @patch('mage_ai.streaming.sinks.generic_io.ConfigFileLoader')
55
+ def setUp(self):
56
+ super().setUp()
57
+ self.test_path = Path(self.repo_path)
58
+ self.test_config_path = self.test_path / 'io_config.yaml'
59
+ sample_yaml = """
60
+ test_profile:
61
+ test_1: test_1
62
+ """
63
+ with self.test_config_path.open('w') as fout:
64
+ fout.write(sample_yaml)
65
+
66
+ def tearDown(self):
67
+ self.test_config_path.unlink()
68
+ super().tearDown()
69
+
56
70
  @patch('mage_ai.streaming.sinks.generic_io.importlib.import_module')
57
- def test_init_client(self, mock_import_module, mock_config_loader):
58
- first_db = True
71
+ def test_init_client(self, mock_import_module):
59
72
  for database in TEST_DATABASES:
60
- mock_objects = self.__mock_objects(mock_import_module, mock_config_loader, database)
73
+ mock_objects = self.__mock_objects(mock_import_module, database)
61
74
 
62
75
  # Assertions
63
- if first_db:
64
- mock_config_loader.assert_called_once_with(
65
- os.path.join(self.repo_path, 'io_config.yaml'), 'test_profile')
66
- mock_import_module.assert_called_once_with(database['module_path'])
67
- mock_objects['io_class'].with_config.assert_called_once_with(
68
- mock_objects['config_loader_instance'])
76
+ mock_import_module.assert_any_call(database['module_path'])
77
+ mock_objects['io_class'].with_config.assert_called_once()
69
78
  mock_objects['io_client'].open.assert_called_once()
70
79
 
71
80
  self.assertEqual(mock_objects['sink'].io_client, mock_objects['io_client'])
72
81
 
73
82
  del mock_objects['sink']
74
83
  mock_objects['io_client'].close.assert_called_once()
75
- first_db = False
76
84
 
77
- @patch('mage_ai.streaming.sinks.generic_io.ConfigFileLoader')
78
85
  @patch('mage_ai.streaming.sinks.generic_io.importlib.import_module')
79
- def test_write(self, mock_import_module, mock_config_loader):
86
+ def test_write(self, mock_import_module):
80
87
  database = TEST_DATABASES[0]
81
- mock_objects = self.__mock_objects(mock_import_module, mock_config_loader, database)
88
+ mock_objects = self.__mock_objects(mock_import_module, database)
82
89
 
83
90
  mock_objects['sink'].batch_write = MagicMock()
84
91
 
@@ -90,11 +97,10 @@ class GenericIOTests(TestCase):
90
97
  # Assertions
91
98
  mock_objects['sink'].batch_write.assert_called_once_with([message])
92
99
 
93
- @patch('mage_ai.streaming.sinks.generic_io.ConfigFileLoader')
94
100
  @patch('mage_ai.streaming.sinks.generic_io.importlib.import_module')
95
- def test_batch_write(self, mock_import_module, mock_config_loader):
101
+ def test_batch_write(self, mock_import_module):
96
102
  database = TEST_DATABASES[0]
97
- mock_objects = self.__mock_objects(mock_import_module, mock_config_loader, database)
103
+ mock_objects = self.__mock_objects(mock_import_module, database)
98
104
  mock_objects['io_client'].export = MagicMock()
99
105
 
100
106
  # Test data
@@ -130,13 +136,12 @@ class GenericIOTests(TestCase):
130
136
  ]),
131
137
  )
132
138
 
133
- def __mock_objects(self, mock_import_module, mock_config_loader, database):
139
+ def __mock_objects(self, mock_import_module, database):
134
140
  mock_io_module = MagicMock()
135
141
  mock_io_class = MagicMock()
136
142
  mock_io_client = MagicMock()
137
143
  mock_import_module.return_value = mock_io_module
138
144
  mock_io_class.with_config.return_value = mock_io_client
139
- mock_config_loader_instance = mock_config_loader.return_value
140
145
  setattr(mock_io_module, database['class_name'], mock_io_class)
141
146
  generic_io_sink = GenericIOSink(dict(
142
147
  connector_type=database['connector_type'],
@@ -146,7 +151,6 @@ class GenericIOTests(TestCase):
146
151
  )
147
152
  ))
148
153
  return dict(
149
- config_loader_instance=mock_config_loader_instance,
150
154
  io_module=mock_io_module,
151
155
  io_class=mock_io_class,
152
156
  io_client=mock_io_client,
@@ -1,9 +1,9 @@
1
- import enum
1
+ from mage_ai.shared.enum import StrEnum
2
2
 
3
3
  API_ENDPOINT = 'https://api.mage.ai/v1/usage_statistics'
4
4
 
5
5
 
6
- class EventNameType(str, enum.Enum):
6
+ class EventNameType(StrEnum):
7
7
  API_ERROR = 'api_error'
8
8
  APPLICATION_ERROR = 'application_error'
9
9
  BLOCK_RUN_ENDED = 'block_run_ended'
@@ -13,14 +13,14 @@ class EventNameType(str, enum.Enum):
13
13
  USAGE_STATISTIC_CREATE = 'usage_statistic.create'
14
14
 
15
15
 
16
- class EventActionType(str, enum.Enum):
16
+ class EventActionType(StrEnum):
17
17
  CREATE = 'create'
18
18
  DENY = 'deny'
19
19
  EXECUTE = 'execute'
20
20
  IMPRESSION = 'impression'
21
21
 
22
22
 
23
- class EventObjectType(str, enum.Enum):
23
+ class EventObjectType(StrEnum):
24
24
  BLOCK = 'block'
25
25
  BLOCK_RUN = 'block_run'
26
26
  CHART = 'chart'