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.
- mage_ai/ai/constants.py +2 -2
- mage_ai/ai/llm_pipeline_wizard.py +5 -3
- mage_ai/ai/openai_client.py +11 -0
- mage_ai/api/constants.py +4 -5
- mage_ai/api/oauth_scope.py +2 -2
- mage_ai/api/operations/constants.py +2 -2
- mage_ai/api/presenters/SyncPresenter.py +4 -1
- mage_ai/authentication/oauth/constants.py +2 -2
- mage_ai/authentication/operation_history/constants.py +2 -2
- mage_ai/authentication/permissions/constants.py +5 -6
- mage_ai/cache/constants.py +2 -2
- mage_ai/cache/dbt/constants.py +2 -3
- mage_ai/cluster_manager/constants.py +2 -2
- mage_ai/cluster_manager/kubernetes/workload_manager.py +3 -2
- mage_ai/command_center/constants.py +13 -13
- mage_ai/data_cleaner/column_types/constants.py +2 -2
- mage_ai/data_cleaner/transformer_actions/column.py +19 -7
- mage_ai/data_cleaner/transformer_actions/constants.py +10 -9
- mage_ai/data_integrations/sources/constants.py +2 -0
- mage_ai/data_preparation/git/utils.py +4 -1
- mage_ai/data_preparation/logging/__init__.py +2 -2
- mage_ai/data_preparation/logging/logger.py +3 -3
- mage_ai/data_preparation/models/block/__init__.py +9 -3
- mage_ai/data_preparation/models/block/data_integration/constants.py +2 -2
- mage_ai/data_preparation/models/block/dbt/constants.py +3 -3
- mage_ai/data_preparation/models/block/dynamic/factory.py +40 -3
- mage_ai/data_preparation/models/block/dynamic/utils.py +31 -33
- mage_ai/data_preparation/models/block/dynamic/variables.py +1 -1
- mage_ai/data_preparation/models/block/settings/dynamic/constants.py +3 -3
- mage_ai/data_preparation/models/block/settings/dynamic/mixins.py +63 -4
- mage_ai/data_preparation/models/block/settings/global_data_products/models.py +2 -2
- mage_ai/data_preparation/models/constants.py +10 -10
- mage_ai/data_preparation/models/global_hooks/constants.py +7 -8
- mage_ai/data_preparation/models/global_hooks/models.py +5 -5
- mage_ai/data_preparation/models/project/constants.py +2 -2
- mage_ai/data_preparation/models/triggers/__init__.py +6 -4
- mage_ai/data_preparation/models/variables/constants.py +5 -5
- mage_ai/data_preparation/models/widget/constants.py +5 -5
- mage_ai/data_preparation/preferences.py +9 -16
- mage_ai/data_preparation/repo_manager.py +2 -2
- mage_ai/data_preparation/sync/__init__.py +2 -2
- mage_ai/data_preparation/templates/data_exporters/streaming/generic_python.py +1 -1
- mage_ai/data_preparation/templates/data_loaders/streaming/nats.yaml +3 -0
- mage_ai/errors/constants.py +2 -2
- mage_ai/io/base.py +28 -15
- mage_ai/io/config.py +3 -3
- mage_ai/io/export_utils.py +2 -2
- mage_ai/io/google_cloud_storage.py +3 -2
- mage_ai/io/io_config.py +3 -2
- mage_ai/io/postgres.py +2 -1
- mage_ai/kernels/magic/constants.py +4 -4
- mage_ai/orchestration/constants.py +2 -2
- mage_ai/orchestration/db/constants.py +2 -2
- mage_ai/orchestration/db/models/oauth.py +5 -5
- mage_ai/orchestration/db/models/schedules.py +28 -8
- mage_ai/orchestration/db/models/schedules_project_platform.py +10 -8
- mage_ai/orchestration/job_manager.py +2 -2
- mage_ai/orchestration/monitor/monitor_stats.py +2 -2
- mage_ai/orchestration/notification/config.py +2 -2
- mage_ai/orchestration/pipeline_scheduler_original.py +4 -12
- mage_ai/orchestration/queue/config.py +2 -2
- mage_ai/orchestration/queue/process_queue.py +3 -3
- mage_ai/presenters/charts/data_sources/constants.py +2 -2
- mage_ai/presenters/interactions/constants.py +4 -4
- mage_ai/presenters/pages/models/constants.py +4 -4
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-663c909dcda4c23a.js → _app-5bdff745074fb350.js} +2 -2
- mage_ai/server/frontend_dist/_next/static/chunks/{webpack-43534cc51fce8644.js → webpack-b9a067f3bd0a3a05.js} +1 -1
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/compute.html +2 -2
- mage_ai/server/frontend_dist/files.html +2 -2
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-data-products.html +2 -2
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/files.html +2 -2
- mage_ai/server/frontend_dist/manage/overview.html +2 -2
- mage_ai/server/frontend_dist/manage/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +2 -2
- mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist/manage/users.html +2 -2
- mage_ai/server/frontend_dist/manage.html +2 -2
- mage_ai/server/frontend_dist/oauth.html +3 -3
- mage_ai/server/frontend_dist/overview.html +2 -2
- mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +5 -5
- mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist/templates.html +2 -2
- mage_ai/server/frontend_dist/terminal.html +2 -2
- mage_ai/server/frontend_dist/test.html +2 -2
- mage_ai/server/frontend_dist/triggers.html +2 -2
- mage_ai/server/frontend_dist/v2/canvas.html +2 -2
- mage_ai/server/frontend_dist/v2.html +2 -2
- mage_ai/server/frontend_dist/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-bb4a0e0d783622a8.js → _app-90de19bc03f1484b.js} +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-9eb1dd2ee735aaac.js → webpack-12ad70eb5c31aa92.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/v2/canvas.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/v2.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
- mage_ai/server/kernel_output_parser.py +2 -3
- mage_ai/server/kernels.py +2 -3
- mage_ai/server/scheduler_manager.py +2 -2
- mage_ai/server/server.py +12 -0
- mage_ai/server/websockets/constants.py +4 -4
- mage_ai/services/compute/aws/constants.py +2 -2
- mage_ai/services/compute/aws/steps.py +16 -10
- mage_ai/services/compute/constants.py +4 -4
- mage_ai/services/compute/models.py +4 -4
- mage_ai/services/k8s/config.py +4 -0
- mage_ai/services/k8s/job_manager.py +2 -0
- mage_ai/services/spark/constants.py +3 -3
- mage_ai/services/spark/models/jobs.py +2 -2
- mage_ai/services/spark/models/sqls.py +2 -2
- mage_ai/services/spark/models/stages.py +4 -4
- mage_ai/services/spark/models/threads.py +2 -2
- mage_ai/settings/backends.py +3 -2
- mage_ai/settings/models/configuration_option.py +3 -3
- mage_ai/settings/server.py +5 -0
- mage_ai/shared/constants.py +3 -3
- mage_ai/shared/custom_logger.py +13 -13
- mage_ai/shared/enum.py +11 -0
- mage_ai/shared/environments.py +1 -1
- mage_ai/shared/logger.py +2 -2
- mage_ai/shared/models.py +2 -1
- mage_ai/streaming/constants.py +3 -3
- mage_ai/streaming/sinks/kafka.py +2 -2
- mage_ai/streaming/sinks/postgres.py +6 -0
- mage_ai/streaming/sources/amazon_sqs.py +2 -2
- mage_ai/streaming/sources/base.py +2 -2
- mage_ai/streaming/sources/kafka.py +20 -4
- mage_ai/streaming/sources/nats_js.py +10 -3
- mage_ai/streaming/sources/shared.py +3 -2
- mage_ai/system/constants.py +2 -2
- mage_ai/tests/api/policies/permissions/test_base_policy_with_permissions.py +2 -2
- mage_ai/tests/data_cleaner/transformer_actions/test_trim_transformer.py +161 -0
- mage_ai/tests/data_preparation/models/block/dbt/test_profiles.py +1 -1
- mage_ai/tests/data_preparation/models/block/dynamic/test_combos.py +1 -1
- mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +3 -2
- mage_ai/tests/data_preparation/models/test_blocks_helper.py +1 -1
- mage_ai/tests/data_preparation/models/variables/test_summarizer.py +1 -1
- mage_ai/tests/data_preparation/sync/test_git_sync.py +6 -6
- mage_ai/tests/orchestration/queue/test_process_queue.py +3 -2
- mage_ai/tests/orchestration/test_pipeline_scheduler.py +1 -0
- mage_ai/tests/settings/test_platform.py +2 -2
- mage_ai/tests/streaming/sinks/test_generic_io.py +25 -21
- mage_ai/usage_statistics/constants.py +4 -4
- {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/METADATA +172 -171
- {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/RECORD +247 -245
- {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/WHEEL +1 -1
- /mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-663c909dcda4c23a.js.LICENSE.txt → _app-5bdff745074fb350.js.LICENSE.txt} +0 -0
- /mage_ai/server/frontend_dist/_next/static/{kxGpiudO3f9aX6FAiqydf → pLWT6Sqd09xYpufCVIqnz}/_buildManifest.js +0 -0
- /mage_ai/server/frontend_dist/_next/static/{kxGpiudO3f9aX6FAiqydf → pLWT6Sqd09xYpufCVIqnz}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{H5pcGxWf1BkhXDRs2BqiI → JQewSAObpbhO0wrdAM6Ng}/_buildManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{H5pcGxWf1BkhXDRs2BqiI → JQewSAObpbhO0wrdAM6Ng}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-bb4a0e0d783622a8.js.LICENSE.txt → _app-90de19bc03f1484b.js.LICENSE.txt} +0 -0
- {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.73.dist-info → mage_ai-0.9.74.dist-info}/entry_points.txt +0 -0
- {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()
|
|
@@ -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=
|
|
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=
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
26
|
-
git_manager_instance_mock.submodules_update.
|
|
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.
|
|
46
|
-
git_manager_instance_mock.submodules_update.
|
|
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.
|
|
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.
|
|
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('
|
|
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,
|
|
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
|
|
@@ -205,12 +205,12 @@ class PlatformSettingsTest(ProjectPlatformMixin):
|
|
|
205
205
|
))
|
|
206
206
|
|
|
207
207
|
def test_platform_settings_full_path(self):
|
|
208
|
-
self.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
73
|
+
mock_objects = self.__mock_objects(mock_import_module, database)
|
|
61
74
|
|
|
62
75
|
# Assertions
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
86
|
+
def test_write(self, mock_import_module):
|
|
80
87
|
database = TEST_DATABASES[0]
|
|
81
|
-
mock_objects = self.__mock_objects(mock_import_module,
|
|
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
|
|
101
|
+
def test_batch_write(self, mock_import_module):
|
|
96
102
|
database = TEST_DATABASES[0]
|
|
97
|
-
mock_objects = self.__mock_objects(mock_import_module,
|
|
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,
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
23
|
+
class EventObjectType(StrEnum):
|
|
24
24
|
BLOCK = 'block'
|
|
25
25
|
BLOCK_RUN = 'block_run'
|
|
26
26
|
CHART = 'chart'
|