mage-ai 0.9.67__py3-none-any.whl → 0.9.69__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.
- mage_ai/api/monitors/BaseMonitor.py +1 -2
- mage_ai/api/policies/PipelinePolicy.py +2 -0
- mage_ai/api/resources/BlockLayoutItemResource.py +2 -2
- mage_ai/api/resources/BlockResource.py +4 -3
- mage_ai/api/resources/CacheItemResource.py +1 -1
- mage_ai/api/resources/GitBranchResource.py +3 -5
- mage_ai/api/resources/PageBlockLayoutResource.py +2 -2
- mage_ai/api/resources/PipelineResource.py +13 -0
- mage_ai/api/resources/PipelineRunResource.py +10 -1
- mage_ai/api/resources/SeedResource.py +2 -1
- mage_ai/api/resources/SessionResource.py +13 -1
- mage_ai/authentication/permissions/constants.py +2 -0
- mage_ai/authentication/permissions/seed.py +32 -21
- mage_ai/authentication/providers/active_directory.py +4 -3
- mage_ai/authentication/providers/okta.py +22 -83
- mage_ai/cache/tag.py +3 -0
- mage_ai/cluster_manager/manage.py +4 -1
- mage_ai/data_preparation/executors/k8s_block_executor.py +8 -1
- mage_ai/data_preparation/executors/k8s_pipeline_executor.py +12 -1
- mage_ai/data_preparation/executors/streaming_pipeline_executor.py +77 -7
- mage_ai/data_preparation/logging/gcs_logger_manager.py +7 -4
- mage_ai/data_preparation/models/block/__init__.py +28 -71
- mage_ai/data_preparation/models/block/block_factory.py +77 -0
- mage_ai/data_preparation/models/block/data_integration/mixins.py +16 -5
- mage_ai/data_preparation/models/block/dbt/block.py +5 -7
- mage_ai/data_preparation/models/block/dynamic/child.py +3 -0
- mage_ai/data_preparation/models/block/dynamic/variables.py +2 -2
- mage_ai/data_preparation/models/block/extension/utils.py +1 -0
- mage_ai/data_preparation/models/block/global_data_product/__init__.py +9 -3
- mage_ai/data_preparation/models/block/integration/__init__.py +13 -9
- mage_ai/data_preparation/models/block/platform/mixins.py +1 -1
- mage_ai/data_preparation/models/block/sql/__init__.py +1 -1
- mage_ai/data_preparation/models/pipeline.py +102 -19
- mage_ai/data_preparation/models/utils.py +6 -0
- mage_ai/data_preparation/models/variable.py +18 -4
- mage_ai/data_preparation/repo_manager.py +3 -2
- mage_ai/data_preparation/shared/utils.py +1 -1
- mage_ai/data_preparation/storage/gcs_storage.py +1 -1
- mage_ai/data_preparation/templates/constants.py +7 -0
- mage_ai/data_preparation/templates/data_exporters/mysql.py +2 -2
- mage_ai/data_preparation/templates/data_exporters/oracledb.py +27 -0
- mage_ai/data_preparation/templates/repo/metadata.yaml +1 -0
- mage_ai/io/bigquery.py +131 -58
- mage_ai/io/export_utils.py +3 -0
- mage_ai/io/mysql.py +38 -6
- mage_ai/io/oracledb.py +138 -3
- mage_ai/io/snowflake.py +152 -29
- mage_ai/io/sql.py +4 -0
- mage_ai/orchestration/db/__init__.py +2 -2
- mage_ai/orchestration/db/models/oauth.py +4 -4
- mage_ai/orchestration/db/models/schedules.py +10 -3
- mage_ai/orchestration/job_manager.py +6 -0
- mage_ai/orchestration/notification/sender.py +8 -0
- mage_ai/orchestration/pipeline_scheduler_original.py +26 -7
- mage_ai/orchestration/queue/celery_queue.py +8 -1
- mage_ai/orchestration/queue/process_queue.py +67 -4
- mage_ai/orchestration/queue/queue.py +8 -0
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/{frontend_dist_base_path_template/_next/static/khKiaJtwrslgMmp4YSa1f → frontend_dist/_next/static/_krrrgup_C-dPOpX36S8I}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/4241-ccd0126f5750cc35.js → frontend_dist/_next/static/chunks/4241-4499461184ba0d23.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5627-237a3de578538022.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7966-5c1786fb7e7a48f5.js → frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js → frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js → frontend_dist/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
- 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/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/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/{frontend_dist/_next/static/vPsMu6Fi2zrHaf2fRXKRO → frontend_dist_base_path_template/_next/static/KLL5mirre9d7_ZeEpaw3s}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/4241-ccd0126f5750cc35.js → frontend_dist_base_path_template/_next/static/chunks/4241-4499461184ba0d23.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5627-237a3de578538022.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/7966-5c1786fb7e7a48f5.js → frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-8bbfa0c19b5e4cb3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-597b74828bf105db.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-90abafc7ed61c582.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/sign-in-7d38b2f7c3e918a1.js → frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9cba3211434a8966.js +1 -0
- 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/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/version-control.html +2 -2
- mage_ai/server/scheduler_manager.py +7 -0
- mage_ai/server/server.py +12 -5
- mage_ai/server/websocket_server.py +1 -0
- mage_ai/services/k8s/job_manager.py +8 -0
- mage_ai/services/slack/slack.py +10 -1
- mage_ai/services/spark/spark.py +9 -2
- mage_ai/settings/backends.py +8 -8
- mage_ai/settings/keys/auth.py +2 -0
- mage_ai/settings/models/configuration_option.py +10 -9
- mage_ai/settings/server.py +1 -1
- mage_ai/shared/files.py +19 -1
- mage_ai/shared/path_fixer.py +3 -0
- mage_ai/streaming/sources/base.py +5 -0
- mage_ai/streaming/sources/influxdb.py +2 -0
- mage_ai/streaming/sources/kafka.py +2 -1
- mage_ai/streaming/sources/mongodb.py +4 -0
- mage_ai/tests/api/endpoints/mixins.py +10 -9
- mage_ai/tests/api/endpoints/test_seeds.py +24 -0
- mage_ai/tests/api/operations/test_sessions.py +53 -2
- mage_ai/tests/authentication/providers/test_okta.py +43 -0
- mage_ai/tests/data_preparation/models/block/dbt/test_block.py +2 -2
- mage_ai/tests/data_preparation/models/block/dbt/test_block_sql.py +1 -1
- mage_ai/tests/data_preparation/models/block/dbt/test_block_yaml.py +1 -1
- mage_ai/tests/data_preparation/models/test_block.py +2 -1
- mage_ai/tests/orchestration/db/models/test_oauth.py +3 -3
- mage_ai/tests/orchestration/queue/test_process_queue.py +1 -0
- mage_ai/tests/orchestration/test_pipeline_scheduler.py +2 -0
- mage_ai/tests/server/test_server.py +8 -4
- mage_ai/tests/settings/models/test_configuration_option.py +2 -2
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/METADATA +6 -6
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/RECORD +263 -259
- mage_ai/server/frontend_dist/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/181-e61915415a976861.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-36377e679da2cd91.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/181-e61915415a976861.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-13563a1ff815f922.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-d3a5fd3119fdb1e4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-42789d698d28a92f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-d05040edba41b2ac.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-36377e679da2cd91.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1b688d61f8efe07a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-ed3331d22d5cff7d.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-d94e48bad89ba1e0.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-f508c2f261297724.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-6826000cdffc36b8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-dde29a463495cebb.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-ab98a7b3a678669e.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{vPsMu6Fi2zrHaf2fRXKRO → _krrrgup_C-dPOpX36S8I}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{khKiaJtwrslgMmp4YSa1f → KLL5mirre9d7_ZeEpaw3s}/_ssgManifest.js +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.67.dist-info → mage_ai-0.9.69.dist-info}/top_level.txt +0 -0
|
@@ -2,9 +2,12 @@ import asyncio
|
|
|
2
2
|
import copy
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
+
import traceback
|
|
5
6
|
from contextlib import redirect_stderr, redirect_stdout
|
|
7
|
+
from datetime import datetime
|
|
6
8
|
from typing import Callable, Dict, List, Union
|
|
7
9
|
|
|
10
|
+
import pytz
|
|
8
11
|
import yaml
|
|
9
12
|
from jinja2 import Template
|
|
10
13
|
|
|
@@ -12,9 +15,14 @@ from mage_ai.data_preparation.executors.pipeline_executor import PipelineExecuto
|
|
|
12
15
|
from mage_ai.data_preparation.logging.logger import DictLogger
|
|
13
16
|
from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
|
|
14
17
|
from mage_ai.data_preparation.models.pipeline import Pipeline
|
|
18
|
+
from mage_ai.data_preparation.shared.retry import RetryConfig
|
|
15
19
|
from mage_ai.data_preparation.shared.stream import StreamToLogger
|
|
16
20
|
from mage_ai.data_preparation.shared.utils import get_template_vars
|
|
21
|
+
from mage_ai.orchestration.db import safe_db_query
|
|
22
|
+
from mage_ai.orchestration.db.models.schedules import PipelineRun
|
|
17
23
|
from mage_ai.shared.hash import merge_dict
|
|
24
|
+
from mage_ai.shared.retry import retry
|
|
25
|
+
from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
18
26
|
|
|
19
27
|
|
|
20
28
|
class StreamingPipelineExecutor(PipelineExecutor):
|
|
@@ -22,6 +30,7 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
22
30
|
super().__init__(pipeline, **kwargs)
|
|
23
31
|
# TODO: Support custom log destination for streaming pipelines
|
|
24
32
|
self.parse_and_validate_blocks()
|
|
33
|
+
self.retry_metadata = dict(attempts=0)
|
|
25
34
|
|
|
26
35
|
def parse_and_validate_blocks(self):
|
|
27
36
|
"""
|
|
@@ -67,6 +76,8 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
67
76
|
self,
|
|
68
77
|
build_block_output_stdout: Callable[..., object] = None,
|
|
69
78
|
global_vars: Dict = None,
|
|
79
|
+
pipeline_run_id: int = None,
|
|
80
|
+
retry_config: Dict = None,
|
|
70
81
|
**kwargs,
|
|
71
82
|
) -> None:
|
|
72
83
|
# TODOs:
|
|
@@ -74,6 +85,7 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
74
85
|
# 2. Support flink pipeline
|
|
75
86
|
|
|
76
87
|
tags = self.build_tags(**kwargs)
|
|
88
|
+
self.logging_tags = tags
|
|
77
89
|
if build_block_output_stdout:
|
|
78
90
|
stdout_logger = logging.getLogger('streaming_pipeline_executor')
|
|
79
91
|
self.logger = DictLogger(stdout_logger)
|
|
@@ -82,24 +94,53 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
82
94
|
self.logger = DictLogger(self.logger_manager.logger, logging_tags=tags)
|
|
83
95
|
stdout = StreamToLogger(self.logger, logging_tags=tags)
|
|
84
96
|
try:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
if retry_config is None:
|
|
98
|
+
retry_config = self.pipeline.retry_config or dict()
|
|
99
|
+
infinite_retries = False if retry_config else False
|
|
100
|
+
|
|
101
|
+
if type(retry_config) is not RetryConfig:
|
|
102
|
+
retry_config = RetryConfig.load(config=retry_config)
|
|
103
|
+
|
|
104
|
+
@retry(
|
|
105
|
+
retries=retry_config.retries,
|
|
106
|
+
delay=retry_config.delay,
|
|
107
|
+
max_delay=retry_config.max_delay,
|
|
108
|
+
exponential_backoff=retry_config.exponential_backoff,
|
|
109
|
+
logger=self.logger,
|
|
110
|
+
logging_tags=self.logging_tags,
|
|
111
|
+
retry_metadata=self.retry_metadata,
|
|
112
|
+
)
|
|
113
|
+
def __execute_with_retry():
|
|
114
|
+
with redirect_stdout(stdout):
|
|
115
|
+
with redirect_stderr(stdout):
|
|
116
|
+
self.__execute_in_python(
|
|
117
|
+
build_block_output_stdout=build_block_output_stdout,
|
|
118
|
+
global_vars=global_vars,
|
|
119
|
+
pipeline_run_id=pipeline_run_id,
|
|
120
|
+
)
|
|
121
|
+
__execute_with_retry()
|
|
91
122
|
except Exception as e:
|
|
92
123
|
if not build_block_output_stdout:
|
|
93
124
|
self.logger.exception(
|
|
94
125
|
f'Failed to execute streaming pipeline {self.pipeline.uuid}',
|
|
95
126
|
**merge_dict(dict(error=e), tags),
|
|
96
127
|
)
|
|
128
|
+
if not infinite_retries:
|
|
129
|
+
# If pipeline retry config is present, fail the pipeline after the retries
|
|
130
|
+
self.__update_pipeline_run_status(
|
|
131
|
+
pipeline_run_id,
|
|
132
|
+
PipelineRun.PipelineRunStatus.FAILED,
|
|
133
|
+
error=e,
|
|
134
|
+
)
|
|
135
|
+
|
|
97
136
|
raise e
|
|
98
137
|
|
|
99
138
|
def __execute_in_python(
|
|
100
139
|
self,
|
|
101
140
|
build_block_output_stdout: Callable[..., object] = None,
|
|
102
|
-
global_vars: Dict = None
|
|
141
|
+
global_vars: Dict = None,
|
|
142
|
+
pipeline_run_id: int = None,
|
|
143
|
+
|
|
103
144
|
):
|
|
104
145
|
from mage_ai.streaming.sinks.sink_factory import SinkFactory
|
|
105
146
|
from mage_ai.streaming.sources.base import SourceConsumeMethod
|
|
@@ -227,6 +268,35 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
227
268
|
for sink in sinks_by_uuid.values():
|
|
228
269
|
sink.destroy()
|
|
229
270
|
|
|
271
|
+
@safe_db_query
|
|
272
|
+
def __update_pipeline_run_status(
|
|
273
|
+
self,
|
|
274
|
+
pipeline_run_id: int,
|
|
275
|
+
status: PipelineRun.PipelineRunStatus,
|
|
276
|
+
error: Exception = None,
|
|
277
|
+
):
|
|
278
|
+
if not pipeline_run_id or not status:
|
|
279
|
+
return
|
|
280
|
+
pipeline_run = PipelineRun.query.get(pipeline_run_id)
|
|
281
|
+
pipeline_run.update(
|
|
282
|
+
status=status,
|
|
283
|
+
completed_at=datetime.now(tz=pytz.UTC),
|
|
284
|
+
)
|
|
285
|
+
if status == PipelineRun.PipelineRunStatus.FAILED:
|
|
286
|
+
asyncio.run(UsageStatisticLogger().pipeline_run_ended(pipeline_run))
|
|
287
|
+
error_msg = None
|
|
288
|
+
stacktrace = None
|
|
289
|
+
if error is not None:
|
|
290
|
+
error_msg = str(error)
|
|
291
|
+
stacktrace = traceback.format_exc()
|
|
292
|
+
notification_sender = self.pipeline.get_notification_sender()
|
|
293
|
+
notification_sender.send_pipeline_run_failure_message(
|
|
294
|
+
pipeline=self.pipeline,
|
|
295
|
+
pipeline_run=pipeline_run,
|
|
296
|
+
error=error_msg,
|
|
297
|
+
stacktrace=stacktrace,
|
|
298
|
+
)
|
|
299
|
+
|
|
230
300
|
def __execute_in_flink(self):
|
|
231
301
|
"""
|
|
232
302
|
TODO: Implement this method
|
|
@@ -10,9 +10,9 @@ from mage_ai.shared.config import BaseConfig
|
|
|
10
10
|
|
|
11
11
|
@dataclass
|
|
12
12
|
class GCSConfig(BaseConfig):
|
|
13
|
-
path_to_credentials: str
|
|
14
13
|
bucket: str
|
|
15
14
|
prefix: str
|
|
15
|
+
path_to_credentials: str = None
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class GCSLoggerManager(LoggerManager):
|
|
@@ -23,9 +23,12 @@ class GCSLoggerManager(LoggerManager):
|
|
|
23
23
|
):
|
|
24
24
|
super().__init__(repo_config=repo_config, **kwargs)
|
|
25
25
|
self.gcs_config = GCSConfig.load(config=self.logging_config.destination_config)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
if self.gcs_config.path_to_credentials:
|
|
27
|
+
credentials = service_account.Credentials.from_service_account_file(
|
|
28
|
+
self.gcs_config.path_to_credentials
|
|
29
|
+
)
|
|
30
|
+
else:
|
|
31
|
+
credentials = None
|
|
29
32
|
self.gcs_client = storage.Client(credentials=credentials)
|
|
30
33
|
|
|
31
34
|
def create_log_filepath_dir(self, path):
|
|
@@ -90,7 +90,7 @@ from mage_ai.data_preparation.templates.data_integrations.utils import get_templ
|
|
|
90
90
|
from mage_ai.data_preparation.templates.template import load_template
|
|
91
91
|
from mage_ai.server.kernel_output_parser import DataType
|
|
92
92
|
from mage_ai.services.spark.config import SparkConfig
|
|
93
|
-
from mage_ai.services.spark.spark import get_spark_session
|
|
93
|
+
from mage_ai.services.spark.spark import SPARK_ENABLED, get_spark_session
|
|
94
94
|
from mage_ai.settings.platform.constants import project_platform_activated
|
|
95
95
|
from mage_ai.settings.repo import get_repo_path
|
|
96
96
|
from mage_ai.shared.array import unique_by
|
|
@@ -723,41 +723,6 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
723
723
|
widget=widget,
|
|
724
724
|
)
|
|
725
725
|
|
|
726
|
-
@classmethod
|
|
727
|
-
def block_class_from_type(self, block_type: str, language=None, pipeline=None) -> 'Block':
|
|
728
|
-
from mage_ai.data_preparation.models.block.constants import BLOCK_TYPE_TO_CLASS
|
|
729
|
-
from mage_ai.data_preparation.models.block.integration import (
|
|
730
|
-
DestinationBlock,
|
|
731
|
-
SourceBlock,
|
|
732
|
-
TransformerBlock,
|
|
733
|
-
)
|
|
734
|
-
from mage_ai.data_preparation.models.block.r import RBlock
|
|
735
|
-
from mage_ai.data_preparation.models.block.sql import SQLBlock
|
|
736
|
-
from mage_ai.data_preparation.models.widget import Widget
|
|
737
|
-
|
|
738
|
-
if BlockType.CHART == block_type:
|
|
739
|
-
return Widget
|
|
740
|
-
elif BlockType.DBT == block_type:
|
|
741
|
-
from mage_ai.data_preparation.models.block.dbt import DBTBlock
|
|
742
|
-
|
|
743
|
-
return DBTBlock
|
|
744
|
-
elif pipeline and PipelineType.INTEGRATION == pipeline.type:
|
|
745
|
-
if BlockType.CALLBACK == block_type:
|
|
746
|
-
return CallbackBlock
|
|
747
|
-
elif BlockType.CONDITIONAL == block_type:
|
|
748
|
-
return ConditionalBlock
|
|
749
|
-
elif BlockType.DATA_LOADER == block_type:
|
|
750
|
-
return SourceBlock
|
|
751
|
-
elif BlockType.DATA_EXPORTER == block_type:
|
|
752
|
-
return DestinationBlock
|
|
753
|
-
else:
|
|
754
|
-
return TransformerBlock
|
|
755
|
-
elif BlockLanguage.SQL == language:
|
|
756
|
-
return SQLBlock
|
|
757
|
-
elif BlockLanguage.R == language:
|
|
758
|
-
return RBlock
|
|
759
|
-
return BLOCK_TYPE_TO_CLASS.get(block_type)
|
|
760
|
-
|
|
761
726
|
@classmethod
|
|
762
727
|
def create(
|
|
763
728
|
self,
|
|
@@ -777,6 +742,8 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
777
742
|
widget: bool = False,
|
|
778
743
|
downstream_block_uuids: List[str] = None,
|
|
779
744
|
) -> 'Block':
|
|
745
|
+
from mage_ai.data_preparation.models.block.block_factory import BlockFactory
|
|
746
|
+
|
|
780
747
|
"""
|
|
781
748
|
1. Create a new folder for block_type if not exist
|
|
782
749
|
2. Create a new python file with code template
|
|
@@ -870,7 +837,11 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
870
837
|
language,
|
|
871
838
|
)
|
|
872
839
|
|
|
873
|
-
block =
|
|
840
|
+
block = BlockFactory.block_class_from_type(
|
|
841
|
+
block_type,
|
|
842
|
+
language=language,
|
|
843
|
+
pipeline=pipeline,
|
|
844
|
+
)(
|
|
874
845
|
name,
|
|
875
846
|
uuid,
|
|
876
847
|
block_type,
|
|
@@ -931,43 +902,16 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
931
902
|
block_uuids[t.value].append(f.split('.')[0])
|
|
932
903
|
return block_uuids
|
|
933
904
|
|
|
934
|
-
@classmethod
|
|
935
|
-
def get_block(
|
|
936
|
-
self,
|
|
937
|
-
name,
|
|
938
|
-
uuid,
|
|
939
|
-
block_type,
|
|
940
|
-
configuration=None,
|
|
941
|
-
content=None,
|
|
942
|
-
language=None,
|
|
943
|
-
pipeline=None,
|
|
944
|
-
status=BlockStatus.NOT_EXECUTED,
|
|
945
|
-
) -> 'Block':
|
|
946
|
-
block_class = self.block_class_from_type(
|
|
947
|
-
block_type,
|
|
948
|
-
language=language,
|
|
949
|
-
pipeline=pipeline,
|
|
950
|
-
) or Block
|
|
951
|
-
return block_class(
|
|
952
|
-
name,
|
|
953
|
-
uuid,
|
|
954
|
-
block_type,
|
|
955
|
-
configuration=configuration,
|
|
956
|
-
content=content,
|
|
957
|
-
language=language,
|
|
958
|
-
pipeline=pipeline,
|
|
959
|
-
status=status,
|
|
960
|
-
)
|
|
961
|
-
|
|
962
905
|
@classmethod
|
|
963
906
|
def get_block_from_file_path(self, file_path: str) -> 'Block':
|
|
964
907
|
parts = get_path_parts(file_path)
|
|
965
908
|
|
|
966
909
|
if parts and len(parts) >= 3:
|
|
910
|
+
from mage_ai.data_preparation.models.block.block_factory import BlockFactory
|
|
911
|
+
|
|
967
912
|
# If file_path == transformers/test4.py
|
|
968
913
|
# parts ==
|
|
969
914
|
# ('/home/src/default_repo/default_platform2/project3', 'transformers', 'test4.py')
|
|
970
|
-
|
|
971
915
|
# If project platform platform activated, then parts ==
|
|
972
916
|
# ('/home/src', 'default_repo', 'data_loaders/astral_violet.py')
|
|
973
917
|
|
|
@@ -986,7 +930,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
986
930
|
configuration = dict(file_path=file_path, file_source=dict(path=file_path))
|
|
987
931
|
language = FILE_EXTENSION_TO_BLOCK_LANGUAGE.get(extension)
|
|
988
932
|
|
|
989
|
-
return
|
|
933
|
+
return BlockFactory.get_block(
|
|
990
934
|
block_uuid,
|
|
991
935
|
block_uuid,
|
|
992
936
|
block_type,
|
|
@@ -2445,8 +2389,10 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
2445
2389
|
return Template(self.executor_type).render(**get_template_vars())
|
|
2446
2390
|
return self.executor_type
|
|
2447
2391
|
|
|
2448
|
-
def get_pipelines_from_cache(self) -> List[Dict]:
|
|
2449
|
-
|
|
2392
|
+
def get_pipelines_from_cache(self, block_cache: BlockCache = None) -> List[Dict]:
|
|
2393
|
+
if block_cache is None:
|
|
2394
|
+
block_cache = BlockCache()
|
|
2395
|
+
arr = block_cache.get_pipelines(self)
|
|
2450
2396
|
|
|
2451
2397
|
return unique_by(
|
|
2452
2398
|
arr,
|
|
@@ -2497,11 +2443,13 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
2497
2443
|
def to_dict(
|
|
2498
2444
|
self,
|
|
2499
2445
|
include_block_catalog: bool = False,
|
|
2446
|
+
include_block_pipelines: bool = False,
|
|
2500
2447
|
include_callback_blocks: bool = False,
|
|
2501
2448
|
include_content: bool = False,
|
|
2502
2449
|
include_outputs: bool = False,
|
|
2503
2450
|
include_outputs_spark: bool = False,
|
|
2504
2451
|
sample_count: int = None,
|
|
2452
|
+
block_cache: BlockCache = None,
|
|
2505
2453
|
check_if_file_exists: bool = False,
|
|
2506
2454
|
**kwargs,
|
|
2507
2455
|
) -> Dict:
|
|
@@ -2515,6 +2463,9 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
2515
2463
|
if include_block_catalog and self.is_data_integration() and self.pipeline:
|
|
2516
2464
|
data['catalog'] = self.get_catalog_from_file()
|
|
2517
2465
|
|
|
2466
|
+
if include_block_pipelines:
|
|
2467
|
+
data['pipelines'] = self.get_pipelines_from_cache(block_cache=block_cache)
|
|
2468
|
+
|
|
2518
2469
|
if include_outputs:
|
|
2519
2470
|
include_outputs_use = include_outputs
|
|
2520
2471
|
if self.is_using_spark() and self.compute_management_enabled():
|
|
@@ -2551,6 +2502,7 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
2551
2502
|
include_outputs: bool = False,
|
|
2552
2503
|
include_outputs_spark: bool = False,
|
|
2553
2504
|
sample_count: int = None,
|
|
2505
|
+
block_cache: BlockCache = None,
|
|
2554
2506
|
check_if_file_exists: bool = False,
|
|
2555
2507
|
**kwargs,
|
|
2556
2508
|
) -> Dict:
|
|
@@ -2596,7 +2548,7 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
2596
2548
|
data['tags'] = self.tags()
|
|
2597
2549
|
|
|
2598
2550
|
if include_block_pipelines:
|
|
2599
|
-
data['pipelines'] = self.get_pipelines_from_cache()
|
|
2551
|
+
data['pipelines'] = self.get_pipelines_from_cache(block_cache=block_cache)
|
|
2600
2552
|
|
|
2601
2553
|
return data
|
|
2602
2554
|
|
|
@@ -3093,6 +3045,8 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
3093
3045
|
return global_vars
|
|
3094
3046
|
|
|
3095
3047
|
def get_spark_session(self):
|
|
3048
|
+
if not SPARK_ENABLED:
|
|
3049
|
+
return None
|
|
3096
3050
|
if self.spark_init and (not self.pipeline or
|
|
3097
3051
|
not self.pipeline.spark_config):
|
|
3098
3052
|
return self.spark
|
|
@@ -3520,12 +3474,15 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
3520
3474
|
|
|
3521
3475
|
cache = BlockCache()
|
|
3522
3476
|
if detach:
|
|
3477
|
+
from mage_ai.data_preparation.models.block.block_factory import (
|
|
3478
|
+
BlockFactory,
|
|
3479
|
+
)
|
|
3523
3480
|
""""
|
|
3524
3481
|
New block added to pipeline, so it must be added to the block cache.
|
|
3525
3482
|
Old block no longer in pipeline, so it must be removed from block cache.
|
|
3526
3483
|
"""
|
|
3527
3484
|
cache.add_pipeline(self, self.pipeline)
|
|
3528
|
-
old_block =
|
|
3485
|
+
old_block = BlockFactory.get_block(
|
|
3529
3486
|
old_uuid,
|
|
3530
3487
|
old_uuid,
|
|
3531
3488
|
self.type,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from mage_ai.data_preparation.models.block import Block, CallbackBlock, ConditionalBlock
|
|
2
|
+
from mage_ai.data_preparation.models.block.constants import BLOCK_TYPE_TO_CLASS
|
|
3
|
+
from mage_ai.data_preparation.models.block.integration import (
|
|
4
|
+
DestinationBlock,
|
|
5
|
+
SourceBlock,
|
|
6
|
+
TransformerBlock,
|
|
7
|
+
)
|
|
8
|
+
from mage_ai.data_preparation.models.block.r import RBlock
|
|
9
|
+
from mage_ai.data_preparation.models.block.sql import SQLBlock
|
|
10
|
+
from mage_ai.data_preparation.models.constants import (
|
|
11
|
+
BlockLanguage,
|
|
12
|
+
BlockStatus,
|
|
13
|
+
BlockType,
|
|
14
|
+
PipelineType,
|
|
15
|
+
)
|
|
16
|
+
from mage_ai.data_preparation.models.widget import Widget
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from mage_ai.data_preparation.models.block.dbt.block_sql import DBTBlockSQL
|
|
20
|
+
from mage_ai.data_preparation.models.block.dbt.block_yaml import DBTBlockYAML
|
|
21
|
+
except Exception:
|
|
22
|
+
print('DBT library not installed.')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class BlockFactory:
|
|
26
|
+
@classmethod
|
|
27
|
+
def block_class_from_type(self, block_type: str, language=None, pipeline=None) -> 'Block':
|
|
28
|
+
if BlockType.CHART == block_type:
|
|
29
|
+
return Widget
|
|
30
|
+
elif BlockType.DBT == block_type:
|
|
31
|
+
if language == BlockLanguage.YAML:
|
|
32
|
+
return DBTBlockYAML
|
|
33
|
+
return DBTBlockSQL
|
|
34
|
+
elif pipeline and PipelineType.INTEGRATION == pipeline.type:
|
|
35
|
+
if BlockType.CALLBACK == block_type:
|
|
36
|
+
return CallbackBlock
|
|
37
|
+
elif BlockType.CONDITIONAL == block_type:
|
|
38
|
+
return ConditionalBlock
|
|
39
|
+
elif BlockType.DATA_LOADER == block_type:
|
|
40
|
+
return SourceBlock
|
|
41
|
+
elif BlockType.DATA_EXPORTER == block_type:
|
|
42
|
+
return DestinationBlock
|
|
43
|
+
else:
|
|
44
|
+
return TransformerBlock
|
|
45
|
+
elif BlockLanguage.SQL == language:
|
|
46
|
+
return SQLBlock
|
|
47
|
+
elif BlockLanguage.R == language:
|
|
48
|
+
return RBlock
|
|
49
|
+
return BLOCK_TYPE_TO_CLASS.get(block_type)
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def get_block(
|
|
53
|
+
self,
|
|
54
|
+
name,
|
|
55
|
+
uuid,
|
|
56
|
+
block_type,
|
|
57
|
+
configuration=None,
|
|
58
|
+
content=None,
|
|
59
|
+
language=None,
|
|
60
|
+
pipeline=None,
|
|
61
|
+
status=BlockStatus.NOT_EXECUTED,
|
|
62
|
+
) -> 'Block':
|
|
63
|
+
block_class = BlockFactory.block_class_from_type(
|
|
64
|
+
block_type,
|
|
65
|
+
language=language,
|
|
66
|
+
pipeline=pipeline,
|
|
67
|
+
) or Block
|
|
68
|
+
return block_class(
|
|
69
|
+
name,
|
|
70
|
+
uuid,
|
|
71
|
+
block_type,
|
|
72
|
+
configuration=configuration,
|
|
73
|
+
content=content,
|
|
74
|
+
language=language,
|
|
75
|
+
pipeline=pipeline,
|
|
76
|
+
status=status,
|
|
77
|
+
)
|
|
@@ -202,18 +202,29 @@ class DataIntegrationMixin:
|
|
|
202
202
|
with open(catalog_full_path, mode='w') as f:
|
|
203
203
|
f.write(json.dumps(catalog))
|
|
204
204
|
|
|
205
|
-
def is_data_integration(self) -> bool:
|
|
205
|
+
def is_data_integration(self, pipeline_project: Project = None) -> bool:
|
|
206
206
|
"""
|
|
207
207
|
Check if the block is a data integration block.
|
|
208
208
|
If the data_integration_in_batch_pipeline feature is not enabled, return False.
|
|
209
209
|
|
|
210
|
+
Args:
|
|
211
|
+
pipeline_project (Project, optional): A cached Project value to avoid
|
|
212
|
+
looking it up many times when called inside loops. Defaults to None.
|
|
213
|
+
|
|
210
214
|
Returns:
|
|
211
215
|
bool: True if it's a data integration block, False otherwise.
|
|
212
216
|
"""
|
|
213
|
-
if not self.pipeline
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
if not self.pipeline:
|
|
218
|
+
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
actual_project: Project = pipeline_project
|
|
222
|
+
if not actual_project:
|
|
223
|
+
actual_project = Project(self.pipeline.repo_config)
|
|
224
|
+
|
|
225
|
+
if not actual_project.is_feature_enabled(
|
|
226
|
+
FeatureUUID.DATA_INTEGRATION_IN_BATCH_PIPELINE,
|
|
227
|
+
):
|
|
217
228
|
|
|
218
229
|
return False
|
|
219
230
|
|
|
@@ -26,19 +26,17 @@ from mage_ai.shared.parsers import encode_complex
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class DBTBlock(Block):
|
|
29
|
-
|
|
29
|
+
@classmethod
|
|
30
|
+
def create(cls, *args, **kwargs) -> 'DBTBlock':
|
|
30
31
|
"""
|
|
31
32
|
Factory for the child blocks
|
|
32
33
|
"""
|
|
33
34
|
# Import Child blocks here to prevent cycle import
|
|
34
35
|
from mage_ai.data_preparation.models.block.dbt.block_sql import DBTBlockSQL
|
|
35
36
|
from mage_ai.data_preparation.models.block.dbt.block_yaml import DBTBlockYAML
|
|
36
|
-
if
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return super(DBTBlock, cls).__new__(DBTBlockSQL)
|
|
40
|
-
else:
|
|
41
|
-
return super(DBTBlock, cls).__new__(cls, *args, **kwargs)
|
|
37
|
+
if kwargs.get('language', BlockLanguage.SQL) == BlockLanguage.YAML:
|
|
38
|
+
return DBTBlockYAML(*args, **kwargs)
|
|
39
|
+
return DBTBlockSQL(*args, **kwargs)
|
|
42
40
|
|
|
43
41
|
@property
|
|
44
42
|
def base_project_path(self) -> Union[str, os.PathLike]:
|
|
@@ -6,7 +6,7 @@ from typing import Any, Dict, List, Tuple, Union
|
|
|
6
6
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
-
from mage_ai.data_preparation.models.constants import BlockLanguage
|
|
9
|
+
from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
|
|
10
10
|
from mage_ai.data_preparation.models.variable import Variable
|
|
11
11
|
from mage_ai.shared.memory import get_memory_usage, get_memory_usage_async
|
|
12
12
|
from mage_ai.shared.strings import to_ordinal_integers
|
|
@@ -470,7 +470,7 @@ def fetch_input_variables_for_dynamic_upstream_blocks(
|
|
|
470
470
|
|
|
471
471
|
# If dynamic child should reduce its output (which means it passes the entire
|
|
472
472
|
# output to its downstream blocks):
|
|
473
|
-
if should_reduce_output(upstream_block):
|
|
473
|
+
if should_reduce_output(upstream_block) and block.type != BlockType.EXTENSION:
|
|
474
474
|
child_data = []
|
|
475
475
|
metadata = {}
|
|
476
476
|
for lazy_variable_set in lazy_variable_controller:
|
|
@@ -2,12 +2,15 @@ from logging import Logger
|
|
|
2
2
|
from typing import Dict, List
|
|
3
3
|
|
|
4
4
|
from mage_ai.data_preparation.models.block import Block
|
|
5
|
-
from mage_ai.data_preparation.models.global_data_product import GlobalDataProduct
|
|
6
|
-
from mage_ai.orchestration.triggers import global_data_product as trigger
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
class GlobalDataProductBlock(Block):
|
|
10
|
-
def get_global_data_product(self)
|
|
8
|
+
def get_global_data_product(self):
|
|
9
|
+
# Avoid circular dependency of Pipeline class
|
|
10
|
+
from mage_ai.data_preparation.models.global_data_product import (
|
|
11
|
+
GlobalDataProduct,
|
|
12
|
+
)
|
|
13
|
+
|
|
11
14
|
override_configuration = (self.configuration or {}).get('global_data_product', {})
|
|
12
15
|
global_data_product = GlobalDataProduct.get(override_configuration.get('uuid'))
|
|
13
16
|
|
|
@@ -31,6 +34,9 @@ class GlobalDataProductBlock(Block):
|
|
|
31
34
|
logging_tags: Dict = None,
|
|
32
35
|
**kwargs,
|
|
33
36
|
) -> List:
|
|
37
|
+
# Avoid circular dependency of Pipeline class
|
|
38
|
+
from mage_ai.orchestration.triggers import global_data_product as trigger
|
|
39
|
+
|
|
34
40
|
trigger.trigger_and_check_status(
|
|
35
41
|
self.get_global_data_product(),
|
|
36
42
|
block=self,
|
|
@@ -155,7 +155,7 @@ class IntegrationBlock(Block):
|
|
|
155
155
|
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
156
156
|
|
|
157
157
|
for line in proc.stdout:
|
|
158
|
-
f.write(line.decode())
|
|
158
|
+
f.write(line.decode())
|
|
159
159
|
print_log_from_line(
|
|
160
160
|
line,
|
|
161
161
|
config=config,
|
|
@@ -416,9 +416,10 @@ class SourceBlock(IntegrationBlock):
|
|
|
416
416
|
class DestinationBlock(IntegrationBlock):
|
|
417
417
|
def to_dict(
|
|
418
418
|
self,
|
|
419
|
-
include_content=False,
|
|
420
|
-
include_outputs=False,
|
|
421
|
-
|
|
419
|
+
include_content: bool = False,
|
|
420
|
+
include_outputs: bool = False,
|
|
421
|
+
include_block_pipelines: bool = False,
|
|
422
|
+
sample_count: int = None,
|
|
422
423
|
check_if_file_exists: bool = False,
|
|
423
424
|
destination_table: str = None,
|
|
424
425
|
state_stream: str = None,
|
|
@@ -444,6 +445,7 @@ class DestinationBlock(IntegrationBlock):
|
|
|
444
445
|
super().to_dict(
|
|
445
446
|
include_content=include_content,
|
|
446
447
|
include_outputs=include_outputs,
|
|
448
|
+
include_block_pipelines=include_block_pipelines,
|
|
447
449
|
sample_count=sample_count,
|
|
448
450
|
check_if_file_exists=check_if_file_exists,
|
|
449
451
|
),
|
|
@@ -452,9 +454,10 @@ class DestinationBlock(IntegrationBlock):
|
|
|
452
454
|
|
|
453
455
|
async def to_dict_async(
|
|
454
456
|
self,
|
|
455
|
-
include_content=False,
|
|
456
|
-
include_outputs=False,
|
|
457
|
-
|
|
457
|
+
include_content: bool = False,
|
|
458
|
+
include_outputs: bool = False,
|
|
459
|
+
include_block_pipelines: bool = False,
|
|
460
|
+
sample_count: int = None,
|
|
458
461
|
check_if_file_exists: bool = False,
|
|
459
462
|
destination_table: str = None,
|
|
460
463
|
state_stream: str = None,
|
|
@@ -463,13 +466,14 @@ class DestinationBlock(IntegrationBlock):
|
|
|
463
466
|
return self.to_dict(
|
|
464
467
|
include_content=include_content,
|
|
465
468
|
include_outputs=include_outputs,
|
|
469
|
+
include_block_pipelines=include_block_pipelines,
|
|
466
470
|
sample_count=sample_count,
|
|
467
471
|
check_if_file_exists=check_if_file_exists,
|
|
468
472
|
destination_table=destination_table,
|
|
469
473
|
state_stream=state_stream,
|
|
470
474
|
)
|
|
471
475
|
|
|
472
|
-
def update(self, data, update_state=False):
|
|
476
|
+
def update(self, data, update_state=False, **kwargs):
|
|
473
477
|
if update_state:
|
|
474
478
|
from mage_ai.data_preparation.models.pipelines.integration_pipeline import (
|
|
475
479
|
IntegrationPipeline,
|
|
@@ -493,7 +497,7 @@ class DestinationBlock(IntegrationBlock):
|
|
|
493
497
|
bookmark_values=bookmark_values
|
|
494
498
|
)
|
|
495
499
|
|
|
496
|
-
return super().update(data)
|
|
500
|
+
return super().update(data, **kwargs)
|
|
497
501
|
|
|
498
502
|
def output_variables(self, execution_partition: str = None) -> List[str]:
|
|
499
503
|
return []
|