mage-ai 0.9.74__py3-none-any.whl → 0.9.79__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/llm_pipeline_wizard.py +6 -4
- mage_ai/ai/openai_client.py +7 -5
- mage_ai/api/policies/PipelineSchedulePolicy.py +1 -0
- mage_ai/api/presenters/PipelineSchedulePresenter.py +11 -2
- mage_ai/api/resources/GitFileResource.py +8 -0
- mage_ai/api/resources/PipelineScheduleResource.py +20 -14
- mage_ai/api/resources/PipelineTriggerResource.py +3 -1
- mage_ai/api/resources/SessionResource.py +2 -2
- mage_ai/api/resources/SyncResource.py +1 -1
- mage_ai/api/resources/UserResource.py +1 -1
- mage_ai/cli/main.py +8 -1
- mage_ai/data_cleaner/analysis/charts.py +1 -1
- mage_ai/data_cleaner/cleaning_rules/reformat_values.py +1 -1
- mage_ai/data_integrations/destinations/constants.py +3 -0
- mage_ai/data_integrations/sources/constants.py +2 -0
- mage_ai/data_preparation/executors/block_executor.py +8 -3
- mage_ai/data_preparation/executors/pipeline_executor.py +35 -19
- mage_ai/data_preparation/git/utils.py +2 -2
- mage_ai/data_preparation/logging/logger_manager.py +31 -2
- mage_ai/data_preparation/models/block/__init__.py +33 -27
- mage_ai/data_preparation/models/block/dbt/dbt_adapter.py +20 -8
- mage_ai/data_preparation/models/block/dynamic/constants.py +0 -1
- mage_ai/data_preparation/models/block/dynamic/counter.py +1 -3
- mage_ai/data_preparation/models/block/outputs.py +7 -1
- mage_ai/data_preparation/models/block/r/__init__.py +16 -5
- mage_ai/data_preparation/models/block/sql/__init__.py +2 -0
- mage_ai/data_preparation/models/block/sql/mssql.py +8 -0
- mage_ai/data_preparation/models/block/sql/utils/shared.py +6 -2
- mage_ai/data_preparation/models/constants.py +4 -1
- mage_ai/data_preparation/models/pipeline.py +11 -2
- mage_ai/data_preparation/models/project/__init__.py +3 -1
- mage_ai/data_preparation/models/triggers/__init__.py +1 -1
- mage_ai/data_preparation/storage/local_storage.py +4 -1
- mage_ai/data_preparation/templates/constants.py +7 -0
- mage_ai/data_preparation/templates/data_exporters/streaming/elasticsearch.yaml +3 -0
- mage_ai/data_preparation/templates/data_loaders/airtable.py +28 -0
- mage_ai/data_preparation/templates/data_loaders/streaming/nats.yaml +6 -3
- mage_ai/data_preparation/templates/repo/io_config.yaml +2 -0
- mage_ai/io/airtable.py +104 -0
- mage_ai/io/base.py +30 -1
- mage_ai/io/bigquery.py +36 -0
- mage_ai/io/config.py +6 -0
- mage_ai/io/mssql.py +21 -9
- mage_ai/io/mysql.py +6 -1
- mage_ai/io/oracledb.py +2 -4
- mage_ai/io/postgres.py +41 -19
- mage_ai/io/qdrant.py +1 -1
- mage_ai/io/redshift.py +13 -0
- mage_ai/io/sql.py +1 -0
- mage_ai/io/utils.py +18 -0
- mage_ai/orchestration/db/__init__.py +23 -3
- mage_ai/orchestration/db/migrations/versions/39d36f1dab73_create_genericjob.py +47 -0
- mage_ai/orchestration/db/models/oauth.py +2 -1
- mage_ai/orchestration/db/models/schedules.py +108 -6
- mage_ai/orchestration/db/models/schedules_project_platform.py +1 -1
- mage_ai/orchestration/db/models/secrets.py +11 -1
- mage_ai/orchestration/job_manager.py +19 -0
- mage_ai/orchestration/metrics/pipeline_run.py +1 -1
- mage_ai/orchestration/notification/sender.py +2 -2
- mage_ai/orchestration/pipeline_scheduler_original.py +150 -6
- mage_ai/orchestration/pipeline_scheduler_project_platform.py +4 -5
- mage_ai/orchestration/queue/config.py +11 -1
- mage_ai/orchestration/queue/process_queue.py +4 -0
- mage_ai/orchestration/utils/distributed_lock.py +8 -1
- mage_ai/orchestration/utils/resources.py +56 -2
- mage_ai/sample_datasets/salary_survey.csv +52 -52
- mage_ai/server/api/base.py +41 -0
- mage_ai/server/api/constants.py +1 -0
- mage_ai/server/api/triggers.py +9 -0
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +3 -3
- mage_ai/server/frontend_dist/_next/static/TUo4RceCdMufBTBTq8CAq/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{1187-839336d276186105.js → 1187-4560c3895e1d7099.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{1598-0adca9dce3ba4c60.js → 1598-cbf3f5a6078fc3f5.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-638a944d24d5abde.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3548-36f746b1824004f2.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{3763-39a5174f6a3924db.js → 3763-aabe2703076636b0.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3782-3e2acb5ed45b582b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/5627-d5e559859dd0e1e0.js → frontend_dist/_next/static/chunks/5627-10e76bafa5a26f5f.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{5699-e49718dfc9eb2854.js → 5699-e99379e332bd0b41.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{7966-163da2621b8c987c.js → 7966-a5a7db345ce81263.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-b697b35dfc4e6e26.js +2 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/compute-ed67fa8e81662e8b.js → frontend_dist/_next/static/chunks/pages/compute-9e2dea78024e3bb4.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/files-e0ecd7ced09a63b2.js → frontend_dist/_next/static/chunks/pages/files-e08c7fe76f968f9c.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/{[...slug]-c7a729477ecda50e.js → [...slug]-30c3807057a4e65b.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-data-products-fd6ae6a358a60a0c.js → global-data-products-8dcb3b31af9e0e39.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-8e50243797a7fe59.js → frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-85a64b64d27214b6.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-hooks-d0c003446332dc0d.js → global-hooks-4ff959d51b8a9502.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{files-a69ed8e9f814490c.js → files-d08a460641d0efaa.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{overview-1aad7093c6d39257.js → overview-aae747f487e08d51.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{pipeline-runs-528d30e0d13b0cc7.js → pipeline-runs-09a842d64a6ada62.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{settings-fb9201d9cf63031d.js → settings-2e98e57d9376a458.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/{[user]-000f5a980a07da39.js → [user]-7be6e41ad66089bb.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-e4e613f6e817a733.js → frontend_dist/_next/static/chunks/pages/manage/users/new-4c088833063bfa07.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/manage-34d718b8a4066c23.js → frontend_dist/_next/static/chunks/pages/manage-868fcd8cbeb265f0.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{oauth-3bfd1b8d7f036726.js → oauth-6ceceb62191dfe8a.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-5f8c100e648efa8a.js → pipeline-runs-2d0136b51b57de93.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-688c652f3296bb9c.js → [...slug]-1ad5238742e25b4c.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-bd11e87d026bfbf9.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{dashboard-1236e36d39b1637d.js → dashboard-0f4f47f721b0723f.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-5ae8efe9e0530212.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-fe91dfb0091f6bc6.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-0d68d4bf6290fefb.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-cf794b2d22a80f31.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-9254358d58f07714.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-a964caef91bed9e1.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-821001e690caebe2.js → monitors-80bebb4401eefe25.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-2eae7cb017027682.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-2d4b2a0800a66b33.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-776b2e5b0b6ceba8.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-03d9bca3bc5e6088.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-707ed8ca942ca802.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/{[...slug]-259143ed3cf59e31.js → [...slug]-8429f17d4146e1ec.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-193045d9836d8d80.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-d25d07db166cbb04.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/platform/global-hooks/{[...slug]-5eeec927e4202b63.js → [...slug]-6834ae87bd668cb2.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/platform/global-hooks-fbe9ad995d46d837.js → frontend_dist/_next/static/chunks/pages/platform/global-hooks-b3f7309a23e592b2.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-fc659962d4015cb3.js → profile-f8b7374385e1f1bf.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-8de68502a9afa299.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-a4f88c334414402b.js → frontend_dist/_next/static/chunks/pages/settings/platform/settings-50fb6a34f3913f1f.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-4deb9579ef99a3c6.js → [...slug]-2e5c098c21ea32b7.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-e0cda2f2bfce8d61.js → permissions-54e4b15b9585bfc4.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-040f83d75d0f6537.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-910257d16c604ebd.js → [...slug]-95088f43034e3c95.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{roles-4f7a0756806cee34.js → roles-e9149e1fcf218f42.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{sync-data-208d6f955204d704.js → sync-data-75b67ae4a00818ef.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-c89dc67e5a1706a8.js → [...slug]-557dda05ca6c6124.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{sign-in-054b33312d3193c3.js → sign-in-593c40985d63fcf7.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/templates/{[...slug]-b6ed6a5d818bfd20.js → [...slug]-252c4b6b818345d5.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{templates-852357bc983af2ea.js → templates-ca528bc607753ab8.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/terminal-1f9c56d671bbc67d.js → frontend_dist/_next/static/chunks/pages/terminal-287362c1defcc96b.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/test-2f83af8c9f1378fe.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-d9de73fb799efed8.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/version-control-ae3469b992a341d6.js → frontend_dist/_next/static/chunks/pages/version-control-573f0225d7a703ed.js} +1 -1
- mage_ai/server/frontend_dist/block-layout.html +3 -3
- mage_ai/server/frontend_dist/compute.html +6 -6
- mage_ai/server/frontend_dist/files.html +6 -6
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +6 -6
- mage_ai/server/frontend_dist/global-data-products.html +6 -6
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +6 -6
- mage_ai/server/frontend_dist/global-hooks.html +6 -6
- mage_ai/server/frontend_dist/index.html +3 -3
- mage_ai/server/frontend_dist/manage/files.html +6 -6
- mage_ai/server/frontend_dist/manage/overview.html +6 -6
- mage_ai/server/frontend_dist/manage/pipeline-runs.html +6 -6
- mage_ai/server/frontend_dist/manage/settings.html +6 -6
- mage_ai/server/frontend_dist/manage/users/[user].html +6 -6
- mage_ai/server/frontend_dist/manage/users/new.html +6 -6
- mage_ai/server/frontend_dist/manage/users.html +6 -6
- mage_ai/server/frontend_dist/manage.html +6 -6
- mage_ai/server/frontend_dist/oauth.html +5 -5
- mage_ai/server/frontend_dist/overview.html +6 -6
- mage_ai/server/frontend_dist/pipeline-runs.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +3 -3
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +6 -6
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +3 -3
- mage_ai/server/frontend_dist/pipelines.html +6 -6
- mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +6 -6
- mage_ai/server/frontend_dist/platform/global-hooks.html +6 -6
- mage_ai/server/frontend_dist/settings/account/profile.html +6 -6
- mage_ai/server/frontend_dist/settings/platform/preferences.html +6 -6
- mage_ai/server/frontend_dist/settings/platform/settings.html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/roles.html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +6 -6
- mage_ai/server/frontend_dist/settings/workspace/users.html +6 -6
- mage_ai/server/frontend_dist/settings.html +3 -3
- mage_ai/server/frontend_dist/sign-in.html +7 -7
- mage_ai/server/frontend_dist/templates/[...slug].html +6 -6
- mage_ai/server/frontend_dist/templates.html +6 -6
- mage_ai/server/frontend_dist/terminal.html +6 -6
- mage_ai/server/frontend_dist/test.html +3 -3
- mage_ai/server/frontend_dist/triggers.html +6 -6
- 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 +6 -6
- mage_ai/server/frontend_dist_base_path_template/404.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/_next/static/2QL-FT4lFR0a9bDZ7lNd9/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1187-839336d276186105.js → 1187-4560c3895e1d7099.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1598-0adca9dce3ba4c60.js → 1598-cbf3f5a6078fc3f5.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-638a944d24d5abde.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-36f746b1824004f2.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3763-39a5174f6a3924db.js → 3763-aabe2703076636b0.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-3e2acb5ed45b582b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/5627-d5e559859dd0e1e0.js → frontend_dist_base_path_template/_next/static/chunks/5627-10e76bafa5a26f5f.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{5699-e49718dfc9eb2854.js → 5699-e99379e332bd0b41.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7966-163da2621b8c987c.js → 7966-a5a7db345ce81263.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-f205accb03b9ff43.js +2 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/compute-ed67fa8e81662e8b.js → frontend_dist_base_path_template/_next/static/chunks/pages/compute-9e2dea78024e3bb4.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/files-e0ecd7ced09a63b2.js → frontend_dist_base_path_template/_next/static/chunks/pages/files-e08c7fe76f968f9c.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/{[...slug]-c7a729477ecda50e.js → [...slug]-30c3807057a4e65b.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-data-products-fd6ae6a358a60a0c.js → global-data-products-8dcb3b31af9e0e39.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-8e50243797a7fe59.js → frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-85a64b64d27214b6.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-hooks-d0c003446332dc0d.js → global-hooks-4ff959d51b8a9502.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{files-a69ed8e9f814490c.js → files-d08a460641d0efaa.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{overview-1aad7093c6d39257.js → overview-aae747f487e08d51.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{pipeline-runs-528d30e0d13b0cc7.js → pipeline-runs-09a842d64a6ada62.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{settings-fb9201d9cf63031d.js → settings-2e98e57d9376a458.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/{[user]-000f5a980a07da39.js → [user]-7be6e41ad66089bb.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/manage/users/new-e4e613f6e817a733.js → frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-4c088833063bfa07.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/manage-34d718b8a4066c23.js → frontend_dist_base_path_template/_next/static/chunks/pages/manage-868fcd8cbeb265f0.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{oauth-3bfd1b8d7f036726.js → oauth-6ceceb62191dfe8a.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-5f8c100e648efa8a.js → pipeline-runs-2d0136b51b57de93.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/{[...slug]-688c652f3296bb9c.js → [...slug]-1ad5238742e25b4c.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-bd11e87d026bfbf9.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{dashboard-1236e36d39b1637d.js → dashboard-0f4f47f721b0723f.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-5ae8efe9e0530212.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-fe91dfb0091f6bc6.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-0d68d4bf6290fefb.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-cf794b2d22a80f31.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-9254358d58f07714.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-a964caef91bed9e1.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{monitors-821001e690caebe2.js → monitors-80bebb4401eefe25.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-2eae7cb017027682.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-2d4b2a0800a66b33.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-776b2e5b0b6ceba8.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-03d9bca3bc5e6088.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-707ed8ca942ca802.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/{[...slug]-259143ed3cf59e31.js → [...slug]-8429f17d4146e1ec.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-193045d9836d8d80.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-d25d07db166cbb04.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/platform/global-hooks/{[...slug]-5eeec927e4202b63.js → [...slug]-6834ae87bd668cb2.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/platform/global-hooks-fbe9ad995d46d837.js → frontend_dist_base_path_template/_next/static/chunks/pages/platform/global-hooks-b3f7309a23e592b2.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/{profile-fc659962d4015cb3.js → profile-f8b7374385e1f1bf.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-8de68502a9afa299.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/settings-a4f88c334414402b.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-50fb6a34f3913f1f.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-4deb9579ef99a3c6.js → [...slug]-2e5c098c21ea32b7.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-e0cda2f2bfce8d61.js → permissions-54e4b15b9585bfc4.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-040f83d75d0f6537.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-910257d16c604ebd.js → [...slug]-95088f43034e3c95.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{roles-4f7a0756806cee34.js → roles-e9149e1fcf218f42.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{sync-data-208d6f955204d704.js → sync-data-75b67ae4a00818ef.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-c89dc67e5a1706a8.js → [...slug]-557dda05ca6c6124.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{sign-in-054b33312d3193c3.js → sign-in-593c40985d63fcf7.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/templates/{[...slug]-b6ed6a5d818bfd20.js → [...slug]-252c4b6b818345d5.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{templates-852357bc983af2ea.js → templates-ca528bc607753ab8.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/terminal-1f9c56d671bbc67d.js → frontend_dist_base_path_template/_next/static/chunks/pages/terminal-287362c1defcc96b.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/test-2f83af8c9f1378fe.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-d9de73fb799efed8.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/version-control-ae3469b992a341d6.js → frontend_dist_base_path_template/_next/static/chunks/pages/version-control-573f0225d7a703ed.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-12ad70eb5c31aa92.js → webpack-5f4be622608d9267.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/compute.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/files.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/index.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage/overview.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage/pipeline-runs.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/manage.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/oauth.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/overview.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +3 -3
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/settings.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +7 -7
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +6 -6
- mage_ai/server/frontend_dist_base_path_template/templates.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/terminal.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/test.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/triggers.html +6 -6
- 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 +6 -6
- mage_ai/server/scheduler_manager.py +2 -0
- mage_ai/server/server.py +13 -0
- mage_ai/server/terminal_server.py +3 -0
- mage_ai/server/utils/output_display.py +5 -3
- mage_ai/services/aws/events/events.py +2 -2
- mage_ai/services/gcp/cloud_run/cloud_run.py +1 -1
- mage_ai/services/teams/config.py +13 -2
- mage_ai/services/teams/teams.py +13 -11
- mage_ai/settings/server.py +12 -1
- mage_ai/shared/constants.py +3 -1
- mage_ai/shared/croniter.py +1398 -0
- mage_ai/shared/enum.py +2 -5
- mage_ai/shared/environments.py +27 -3
- mage_ai/streaming/sinks/elasticsearch.py +15 -5
- mage_ai/streaming/sinks/kafka.py +21 -3
- mage_ai/streaming/sources/kafka.py +64 -7
- mage_ai/streaming/sources/kafka_oauth.py +182 -0
- mage_ai/tests/api/endpoints/test_blocks.py +1 -101
- mage_ai/tests/api/endpoints/test_configuration_options.py +1 -48
- mage_ai/tests/api/endpoints/test_configuration_options_project_platform.py +68 -0
- mage_ai/tests/api/endpoints/test_custom_designs.py +1 -106
- mage_ai/tests/api/endpoints/test_custom_designs_project_platform.py +132 -0
- mage_ai/tests/api/endpoints/test_dbt_blocks.py +111 -0
- mage_ai/tests/api/endpoints/test_file_contents.py +0 -48
- mage_ai/tests/api/endpoints/test_file_contents_with_project_platform.py +66 -0
- mage_ai/tests/api/endpoints/test_pipelines.py +0 -134
- mage_ai/tests/api/endpoints/test_pipelines_with_project_platform.py +143 -0
- mage_ai/tests/data_preparation/executors/test_block_executor.py +3 -3
- mage_ai/tests/data_preparation/logging/test_logger_manager.py +24 -5
- mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +1 -3
- mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +3 -3
- mage_ai/tests/data_preparation/models/test_block.py +7 -0
- mage_ai/tests/data_preparation/models/test_pipeline.py +55 -0
- mage_ai/tests/data_preparation/models/test_variable.py +2 -0
- mage_ai/tests/data_preparation/test_repo_manager.py +0 -63
- mage_ai/tests/data_preparation/test_repo_manager_project_platform.py +67 -0
- mage_ai/tests/data_preparation/test_variable_manager.py +0 -51
- mage_ai/tests/data_preparation/test_variable_manager_project_platform.py +41 -0
- mage_ai/tests/io/create_table/test_postgresql.py +28 -0
- mage_ai/tests/orchestration/db/models/test_schedules.py +1 -1
- mage_ai/tests/orchestration/notification/test_config.py +3 -3
- mage_ai/tests/orchestration/notification/test_sender.py +5 -1
- mage_ai/tests/orchestration/utils/__init__.py +0 -0
- mage_ai/tests/orchestration/utils/test_resources.py +235 -0
- mage_ai/tests/shared/test_croniter.py +2541 -0
- mage_ai/tests/streaming/sinks/test_kafka.py +130 -0
- mage_ai/tests/streaming/sources/test_kafka.py +125 -3
- mage_ai/tests/streaming/sources/test_kafka_oauth.py +208 -0
- mage_ai/tests/streaming/sources/test_kafka_raw_value.py +105 -0
- mage_ai/usage_statistics/logger.py +99 -15
- mage_ai-0.9.79.dist-info/METADATA +358 -0
- {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/RECORD +377 -359
- {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/WHEEL +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1557-1ad0c64c2d08e569.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-d65056b6b5e124eb.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3548-b2c5edfb710886a6.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3782-4b3091e550f809a2.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-5bdff745074fb350.js +0 -2
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-a5e9d77ed5b50205.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-69af3253ad0d0d89.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-fe112809feb25b05.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e9ca358209cdf93d.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-a29f1615d2e7d330.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-6d382ae5bad9745c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-cd49372ae1702963.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-135be8974f7f5f2b.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-3af13e89adff4d6c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-b578b075a8d857e3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-058d283ee178c038.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-7b02bb70462144cb.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-5212c01a9dc558da.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/test-86b12cc12d4a625f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/triggers-2481c40b18d5b6d4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/pLWT6Sqd09xYpufCVIqnz/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/JQewSAObpbhO0wrdAM6Ng/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-1ad0c64c2d08e569.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d65056b6b5e124eb.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-b2c5edfb710886a6.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-4b3091e550f809a2.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-90de19bc03f1484b.js +0 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-a5e9d77ed5b50205.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-69af3253ad0d0d89.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-fe112809feb25b05.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e9ca358209cdf93d.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-a29f1615d2e7d330.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-6d382ae5bad9745c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-cd49372ae1702963.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-135be8974f7f5f2b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-3af13e89adff4d6c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-b578b075a8d857e3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-058d283ee178c038.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-7b02bb70462144cb.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-5212c01a9dc558da.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/test-86b12cc12d4a625f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/triggers-2481c40b18d5b6d4.js +0 -1
- mage_ai-0.9.74.dist-info/METADATA +0 -544
- /mage_ai/server/frontend_dist/_next/static/{pLWT6Sqd09xYpufCVIqnz → TUo4RceCdMufBTBTq8CAq}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-5bdff745074fb350.js.LICENSE.txt → _app-b697b35dfc4e6e26.js.LICENSE.txt} +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{JQewSAObpbhO0wrdAM6Ng → 2QL-FT4lFR0a9bDZ7lNd9}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-90de19bc03f1484b.js.LICENSE.txt → _app-f205accb03b9ff43.js.LICENSE.txt} +0 -0
- {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info/licenses}/LICENSE +0 -0
- {mage_ai-0.9.74.dist-info → mage_ai-0.9.79.dist-info}/top_level.txt +0 -0
mage_ai/shared/enum.py
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
try:
|
|
2
2
|
# breaking change introduced in python 3.11
|
|
3
|
-
from enum import Enum, IntEnum, StrEnum
|
|
3
|
+
from enum import Enum, IntEnum, StrEnum # noqa: F401
|
|
4
4
|
except ImportError: # pragma: no cover
|
|
5
|
-
from enum import Enum # pragma: no cover
|
|
6
|
-
|
|
7
|
-
class IntEnum(int, Enum): # pragma: no cover
|
|
8
|
-
pass # pragma: no cover
|
|
5
|
+
from enum import Enum, IntEnum # noqa: F401 # pragma: no cover
|
|
9
6
|
|
|
10
7
|
class StrEnum(str, Enum): # pragma: no cover
|
|
11
8
|
pass # pragma: no cover
|
mage_ai/shared/environments.py
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
|
|
4
|
-
from mage_ai.shared.constants import
|
|
4
|
+
from mage_ai.shared.constants import (
|
|
5
|
+
ENV_DEV,
|
|
6
|
+
ENV_PROD,
|
|
7
|
+
ENV_STAGING,
|
|
8
|
+
ENV_TEST,
|
|
9
|
+
ENV_TEST_MAGE,
|
|
10
|
+
)
|
|
5
11
|
|
|
6
12
|
|
|
7
13
|
def is_deus_ex_machina():
|
|
@@ -16,10 +22,26 @@ def is_dev():
|
|
|
16
22
|
return os.getenv('ENV', None) == 'dev' or os.getenv('ENV', None) == 'development'
|
|
17
23
|
|
|
18
24
|
|
|
19
|
-
def
|
|
25
|
+
def is_test_mage():
|
|
26
|
+
"""
|
|
27
|
+
The "test_mage" environment is used for running unit tests in the CI/CD pipeline.
|
|
28
|
+
When running unit tests, a "test.db" sqlite database is temporarily created for
|
|
29
|
+
storing test metadata. Refer to the mage_ai/orchestration/db/__init__.py file for
|
|
30
|
+
implementation details. The test_mage environment is separate from the "test"
|
|
31
|
+
environment so that Mage's unit tests don't affect a user's own testing metadata db.
|
|
32
|
+
"""
|
|
20
33
|
return os.getenv('ENV', None) == 'test_mage' or any('unittest' in v for v in sys.argv)
|
|
21
34
|
|
|
22
35
|
|
|
36
|
+
def is_test():
|
|
37
|
+
"""
|
|
38
|
+
The "test" environment is the default environment for testing where users may have
|
|
39
|
+
their own specific tests that they want to run with their own test metadata db at a
|
|
40
|
+
specific location.
|
|
41
|
+
"""
|
|
42
|
+
return os.getenv('ENV', None) == 'test' or is_test_mage()
|
|
43
|
+
|
|
44
|
+
|
|
23
45
|
def is_production():
|
|
24
46
|
return os.getenv('ENV', None) == 'production' or os.getenv('ENV', None) == 'prod'
|
|
25
47
|
|
|
@@ -29,7 +51,9 @@ def is_staging():
|
|
|
29
51
|
|
|
30
52
|
|
|
31
53
|
def get_env():
|
|
32
|
-
if
|
|
54
|
+
if is_test_mage():
|
|
55
|
+
return ENV_TEST_MAGE
|
|
56
|
+
elif is_test():
|
|
33
57
|
return ENV_TEST
|
|
34
58
|
elif is_production():
|
|
35
59
|
return ENV_PROD
|
|
@@ -16,6 +16,8 @@ class ElasticSearchConfig(BaseConfig):
|
|
|
16
16
|
api_key: str = None
|
|
17
17
|
ca_cert: str = None
|
|
18
18
|
_id: str = None
|
|
19
|
+
_op_type: str = None
|
|
20
|
+
_source: str = None
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
class ElasticSearchSink(BaseSink):
|
|
@@ -51,9 +53,17 @@ class ElasticSearchSink(BaseSink):
|
|
|
51
53
|
|
|
52
54
|
def batch_write(self, messages: List[Dict]):
|
|
53
55
|
self._print(f'Batch ingest data {messages}, time={time.time()}')
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
docs = []
|
|
57
|
+
for msg in messages:
|
|
58
|
+
doc = {'_index': self.config.index_name}
|
|
59
|
+
if self.config._id is not None:
|
|
60
|
+
doc['id'] = msg[self.config._id]
|
|
61
|
+
if self.config._op_type is not None:
|
|
62
|
+
doc['_op_type'] = self.config._op_type
|
|
63
|
+
if self.config._source is not None:
|
|
64
|
+
doc[self.config._source] = msg
|
|
65
|
+
else:
|
|
66
|
+
doc['_doc'] = msg
|
|
67
|
+
docs.append(doc)
|
|
68
|
+
|
|
59
69
|
helpers.bulk(self.client, docs)
|
mage_ai/streaming/sinks/kafka.py
CHANGED
|
@@ -4,7 +4,6 @@ from dataclasses import dataclass
|
|
|
4
4
|
from typing import Dict, List
|
|
5
5
|
|
|
6
6
|
from kafka import KafkaProducer
|
|
7
|
-
|
|
8
7
|
from mage_ai.shared.config import BaseConfig
|
|
9
8
|
from mage_ai.shared.enum import StrEnum
|
|
10
9
|
from mage_ai.streaming.constants import DEFAULT_BATCH_SIZE, DEFAULT_TIMEOUT_MS
|
|
@@ -12,6 +11,7 @@ from mage_ai.streaming.sinks.base import BaseSink
|
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class SecurityProtocol(StrEnum):
|
|
14
|
+
SASL_PLAINTEXT = 'SASL_PLAINTEXT'
|
|
15
15
|
SASL_SSL = 'SASL_SSL'
|
|
16
16
|
SSL = 'SSL'
|
|
17
17
|
|
|
@@ -21,6 +21,11 @@ class SASLConfig:
|
|
|
21
21
|
mechanism: str = 'PLAIN'
|
|
22
22
|
username: str = None
|
|
23
23
|
password: str = None
|
|
24
|
+
# OAuth configuration for OAUTHBEARER mechanism
|
|
25
|
+
oauth_token_url: str = None
|
|
26
|
+
oauth_client_id: str = None
|
|
27
|
+
oauth_client_secret: str = None
|
|
28
|
+
oauth_scope: str = None
|
|
24
29
|
|
|
25
30
|
|
|
26
31
|
@dataclass
|
|
@@ -84,10 +89,23 @@ class KafkaSink(BaseSink):
|
|
|
84
89
|
kwargs['ssl_password'] = self.config.ssl_config.password
|
|
85
90
|
kwargs['ssl_check_hostname'] = self.config.ssl_config.check_hostname
|
|
86
91
|
elif self.config.security_protocol == SecurityProtocol.SASL_SSL:
|
|
92
|
+
if not self.config.sasl_config:
|
|
93
|
+
raise Exception('sasl_config is required when security_protocol is SASL_SSL')
|
|
87
94
|
kwargs['security_protocol'] = SecurityProtocol.SASL_SSL
|
|
88
95
|
kwargs['sasl_mechanism'] = self.config.sasl_config.mechanism
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
|
|
97
|
+
# Handle OAUTHBEARER mechanism
|
|
98
|
+
if self.config.sasl_config.mechanism == 'OAUTHBEARER':
|
|
99
|
+
from mage_ai.streaming.sources.kafka_oauth import (
|
|
100
|
+
create_oauth_token_provider,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
token_provider = create_oauth_token_provider(self.config.sasl_config)
|
|
104
|
+
kwargs['sasl_oauth_token_provider'] = token_provider
|
|
105
|
+
else:
|
|
106
|
+
# Handle PLAIN, SCRAM mechanisms
|
|
107
|
+
kwargs['sasl_plain_username'] = self.config.sasl_config.username
|
|
108
|
+
kwargs['sasl_plain_password'] = self.config.sasl_config.password
|
|
91
109
|
|
|
92
110
|
if self.config.ssl_config is not None and self.config.ssl_config.cafile:
|
|
93
111
|
kwargs['ssl_cafile'] = self.config.ssl_config.cafile
|
|
@@ -11,7 +11,6 @@ from dataclasses import dataclass, field
|
|
|
11
11
|
from typing import Callable, Dict, List
|
|
12
12
|
|
|
13
13
|
from kafka import KafkaConsumer, TopicPartition
|
|
14
|
-
|
|
15
14
|
from mage_ai.shared.config import BaseConfig
|
|
16
15
|
from mage_ai.shared.enum import StrEnum
|
|
17
16
|
from mage_ai.streaming.constants import DEFAULT_BATCH_SIZE, DEFAULT_TIMEOUT_MS
|
|
@@ -30,6 +29,11 @@ class SASLConfig:
|
|
|
30
29
|
mechanism: str = 'PLAIN'
|
|
31
30
|
username: str = None
|
|
32
31
|
password: str = None
|
|
32
|
+
# OAuth configuration for OAUTHBEARER mechanism
|
|
33
|
+
oauth_token_url: str = None
|
|
34
|
+
oauth_client_id: str = None
|
|
35
|
+
oauth_client_secret: str = None
|
|
36
|
+
oauth_scope: str = None
|
|
33
37
|
|
|
34
38
|
|
|
35
39
|
@dataclass
|
|
@@ -91,9 +95,11 @@ class KafkaSource(BaseSource):
|
|
|
91
95
|
api_version=self.config.api_version,
|
|
92
96
|
auto_offset_reset=self.config.auto_offset_reset,
|
|
93
97
|
max_partition_fetch_bytes=self.config.max_partition_fetch_bytes,
|
|
94
|
-
enable_auto_commit=
|
|
98
|
+
enable_auto_commit=False,
|
|
95
99
|
)
|
|
96
100
|
if self.config.security_protocol == SecurityProtocol.SSL:
|
|
101
|
+
if not self.config.ssl_config:
|
|
102
|
+
raise Exception('ssl_config is required when security_protocol is SSL')
|
|
97
103
|
consumer_kwargs['security_protocol'] = SecurityProtocol.SSL
|
|
98
104
|
consumer_kwargs['ssl_cafile'] = self.config.ssl_config.cafile
|
|
99
105
|
consumer_kwargs['ssl_certfile'] = self.config.ssl_config.certfile
|
|
@@ -103,10 +109,23 @@ class KafkaSource(BaseSource):
|
|
|
103
109
|
'ssl_check_hostname'
|
|
104
110
|
] = self.config.ssl_config.check_hostname
|
|
105
111
|
elif self.config.security_protocol == SecurityProtocol.SASL_SSL:
|
|
112
|
+
if not self.config.sasl_config:
|
|
113
|
+
raise Exception('sasl_config is required when security_protocol is SASL_SSL')
|
|
106
114
|
consumer_kwargs['security_protocol'] = SecurityProtocol.SASL_SSL
|
|
107
115
|
consumer_kwargs['sasl_mechanism'] = self.config.sasl_config.mechanism
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
|
|
117
|
+
# Handle OAUTHBEARER mechanism
|
|
118
|
+
if self.config.sasl_config.mechanism == 'OAUTHBEARER':
|
|
119
|
+
from mage_ai.streaming.sources.kafka_oauth import (
|
|
120
|
+
create_oauth_token_provider,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
token_provider = create_oauth_token_provider(self.config.sasl_config)
|
|
124
|
+
consumer_kwargs['sasl_oauth_token_provider'] = token_provider
|
|
125
|
+
else:
|
|
126
|
+
# Handle PLAIN, SCRAM mechanisms
|
|
127
|
+
consumer_kwargs['sasl_plain_username'] = self.config.sasl_config.username
|
|
128
|
+
consumer_kwargs['sasl_plain_password'] = self.config.sasl_config.password
|
|
110
129
|
|
|
111
130
|
if self.config.ssl_config:
|
|
112
131
|
consumer_kwargs[
|
|
@@ -121,10 +140,27 @@ class KafkaSource(BaseSource):
|
|
|
121
140
|
consumer_kwargs['ssl_password'] = self.config.ssl_config.password
|
|
122
141
|
|
|
123
142
|
elif self.config.security_protocol == SecurityProtocol.SASL_PLAINTEXT:
|
|
143
|
+
if not self.config.sasl_config:
|
|
144
|
+
raise Exception('sasl_config is required when security_protocol is SASL_PLAINTEXT')
|
|
124
145
|
consumer_kwargs['security_protocol'] = SecurityProtocol.SASL_PLAINTEXT
|
|
125
146
|
consumer_kwargs['sasl_mechanism'] = self.config.sasl_config.mechanism
|
|
126
|
-
|
|
127
|
-
|
|
147
|
+
|
|
148
|
+
# Handle OAUTHBEARER mechanism
|
|
149
|
+
if self.config.sasl_config.mechanism == 'OAUTHBEARER':
|
|
150
|
+
self._print(
|
|
151
|
+
'WARNING: Using OAUTHBEARER with SASL_PLAINTEXT is not recommended. '
|
|
152
|
+
'OAuth tokens should be used with SASL_SSL for secure transmission.'
|
|
153
|
+
)
|
|
154
|
+
from mage_ai.streaming.sources.kafka_oauth import (
|
|
155
|
+
create_oauth_token_provider,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
token_provider = create_oauth_token_provider(self.config.sasl_config)
|
|
159
|
+
consumer_kwargs['sasl_oauth_token_provider'] = token_provider
|
|
160
|
+
else:
|
|
161
|
+
# Handle PLAIN, SCRAM mechanisms
|
|
162
|
+
consumer_kwargs['sasl_plain_username'] = self.config.sasl_config.username
|
|
163
|
+
consumer_kwargs['sasl_plain_password'] = self.config.sasl_config.password
|
|
128
164
|
|
|
129
165
|
if self.config.topic:
|
|
130
166
|
topics = [self.config.topic]
|
|
@@ -171,12 +207,32 @@ class KafkaSource(BaseSource):
|
|
|
171
207
|
self.registry_client, self.config.topic
|
|
172
208
|
)
|
|
173
209
|
|
|
210
|
+
def _decode_key(self, key):
|
|
211
|
+
"""Decode message key based on serialization method.
|
|
212
|
+
|
|
213
|
+
When using RAW_VALUE, keep key as raw bytes.
|
|
214
|
+
Otherwise, attempt UTF-8 decode with fallback to raw bytes on error.
|
|
215
|
+
"""
|
|
216
|
+
if not key:
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
# Keep as raw bytes for RAW_VALUE serialization
|
|
220
|
+
if (self.config.serde_config and
|
|
221
|
+
self.config.serde_config.serialization_method == SerializationMethod.RAW_VALUE):
|
|
222
|
+
return key
|
|
223
|
+
|
|
224
|
+
# Attempt UTF-8 decode, fallback to raw bytes on error
|
|
225
|
+
try:
|
|
226
|
+
return key.decode('utf-8')
|
|
227
|
+
except UnicodeDecodeError:
|
|
228
|
+
return key
|
|
229
|
+
|
|
174
230
|
def _convert_message(self, message):
|
|
175
231
|
if self.config.include_metadata:
|
|
176
232
|
message = {
|
|
177
233
|
'data': self.__deserialize_message(message.value),
|
|
178
234
|
'metadata': {
|
|
179
|
-
'key':
|
|
235
|
+
'key': self._decode_key(message.key),
|
|
180
236
|
'partition': message.partition,
|
|
181
237
|
'offset': message.offset,
|
|
182
238
|
'time': int(message.timestamp),
|
|
@@ -270,6 +326,7 @@ class KafkaSource(BaseSource):
|
|
|
270
326
|
message_values.append(message)
|
|
271
327
|
if len(message_values) > 0:
|
|
272
328
|
handler(message_values)
|
|
329
|
+
self.consumer.commit()
|
|
273
330
|
|
|
274
331
|
def test_connection(self):
|
|
275
332
|
self.consumer._client.check_version(timeout=5)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OAuth token provider for Kafka SASL OAUTHBEARER authentication.
|
|
3
|
+
|
|
4
|
+
This module provides a token provider implementation for OAuth 2.0 client credentials flow,
|
|
5
|
+
which can be used with kafka-python's OAUTHBEARER SASL mechanism.
|
|
6
|
+
"""
|
|
7
|
+
import logging
|
|
8
|
+
import time
|
|
9
|
+
from typing import Dict, Optional
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from kafka.sasl.oauth import AbstractTokenProvider
|
|
15
|
+
except ImportError:
|
|
16
|
+
# Fallback for when kafka is not installed
|
|
17
|
+
class AbstractTokenProvider:
|
|
18
|
+
"""Fallback token provider interface when kafka-python is not installed."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, **config):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def token(self):
|
|
24
|
+
raise NotImplementedError("token() must be implemented by subclass")
|
|
25
|
+
|
|
26
|
+
def extensions(self):
|
|
27
|
+
return {}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def create_oauth_token_provider(sasl_config):
|
|
34
|
+
"""
|
|
35
|
+
Create an OAuth token provider for OAUTHBEARER mechanism.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
sasl_config: SASL configuration containing OAuth parameters
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
ClientCredentialsTokenProvider instance
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
Exception: If required OAuth parameters are missing
|
|
45
|
+
"""
|
|
46
|
+
if not sasl_config.oauth_token_url:
|
|
47
|
+
raise Exception(
|
|
48
|
+
'oauth_token_url is required in sasl_config for OAUTHBEARER mechanism'
|
|
49
|
+
)
|
|
50
|
+
if not sasl_config.oauth_client_id:
|
|
51
|
+
raise Exception(
|
|
52
|
+
'oauth_client_id is required in sasl_config for OAUTHBEARER mechanism'
|
|
53
|
+
)
|
|
54
|
+
if not sasl_config.oauth_client_secret:
|
|
55
|
+
raise Exception(
|
|
56
|
+
'oauth_client_secret is required in sasl_config for OAUTHBEARER mechanism'
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return ClientCredentialsTokenProvider(
|
|
60
|
+
token_url=sasl_config.oauth_token_url,
|
|
61
|
+
client_id=sasl_config.oauth_client_id,
|
|
62
|
+
client_secret=sasl_config.oauth_client_secret,
|
|
63
|
+
scope=sasl_config.oauth_scope,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ClientCredentialsTokenProvider(AbstractTokenProvider):
|
|
68
|
+
"""
|
|
69
|
+
Token provider that implements OAuth 2.0 client credentials flow.
|
|
70
|
+
|
|
71
|
+
This provider fetches access tokens from an OAuth 2.0 authorization server
|
|
72
|
+
(e.g., Keycloak) using client credentials and manages token refresh.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
token_url: The OAuth 2.0 token endpoint URL
|
|
76
|
+
client_id: The OAuth 2.0 client ID
|
|
77
|
+
client_secret: The OAuth 2.0 client secret
|
|
78
|
+
scope: Optional scope for the token request
|
|
79
|
+
token_expiry_buffer: Buffer time in seconds before token expiry to refresh (default: 60)
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
token_url: str,
|
|
85
|
+
client_id: str,
|
|
86
|
+
client_secret: str,
|
|
87
|
+
scope: Optional[str] = None,
|
|
88
|
+
token_expiry_buffer: int = 60,
|
|
89
|
+
**config
|
|
90
|
+
):
|
|
91
|
+
super().__init__(**config)
|
|
92
|
+
self.token_url = token_url
|
|
93
|
+
self.client_id = client_id
|
|
94
|
+
self.client_secret = client_secret
|
|
95
|
+
self.scope = scope
|
|
96
|
+
self.token_expiry_buffer = token_expiry_buffer
|
|
97
|
+
|
|
98
|
+
self._access_token: Optional[str] = None
|
|
99
|
+
self._token_expiry_time: Optional[float] = None
|
|
100
|
+
|
|
101
|
+
def token(self) -> str:
|
|
102
|
+
"""
|
|
103
|
+
Returns a valid access token, fetching a new one if necessary.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
str: The access token to use for authentication
|
|
107
|
+
"""
|
|
108
|
+
if self._is_token_expired():
|
|
109
|
+
self._fetch_token()
|
|
110
|
+
|
|
111
|
+
return self._access_token
|
|
112
|
+
|
|
113
|
+
def _is_token_expired(self) -> bool:
|
|
114
|
+
"""
|
|
115
|
+
Check if the current token is expired or will expire soon.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
bool: True if token is expired or will expire within buffer time
|
|
119
|
+
"""
|
|
120
|
+
if self._access_token is None or self._token_expiry_time is None:
|
|
121
|
+
return True
|
|
122
|
+
|
|
123
|
+
current_time = time.time()
|
|
124
|
+
return current_time >= (self._token_expiry_time - self.token_expiry_buffer)
|
|
125
|
+
|
|
126
|
+
def _fetch_token(self):
|
|
127
|
+
"""
|
|
128
|
+
Fetch a new access token from the OAuth 2.0 authorization server.
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
RuntimeError: If token fetch fails
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
data = {
|
|
135
|
+
'grant_type': 'client_credentials',
|
|
136
|
+
'client_id': self.client_id,
|
|
137
|
+
'client_secret': self.client_secret,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if self.scope:
|
|
141
|
+
data['scope'] = self.scope
|
|
142
|
+
|
|
143
|
+
logger.debug(f"Fetching OAuth token from {self.token_url}")
|
|
144
|
+
|
|
145
|
+
response = requests.post(
|
|
146
|
+
self.token_url,
|
|
147
|
+
data=data,
|
|
148
|
+
headers={'Content-Type': 'application/x-www-form-urlencoded'},
|
|
149
|
+
timeout=10,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
response.raise_for_status()
|
|
153
|
+
token_data = response.json()
|
|
154
|
+
|
|
155
|
+
# Validate that access_token is present in the response
|
|
156
|
+
if 'access_token' not in token_data:
|
|
157
|
+
logger.error("OAuth server response missing 'access_token' field")
|
|
158
|
+
raise RuntimeError(
|
|
159
|
+
"Invalid token response format: missing 'access_token' field"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
self._access_token = token_data['access_token']
|
|
163
|
+
expires_in = token_data.get('expires_in', 3600)
|
|
164
|
+
self._token_expiry_time = time.time() + expires_in
|
|
165
|
+
|
|
166
|
+
logger.debug(f"Successfully fetched OAuth token, expires in {expires_in} seconds")
|
|
167
|
+
|
|
168
|
+
except requests.exceptions.RequestException as e:
|
|
169
|
+
logger.error(f"Failed to fetch OAuth token: {e}")
|
|
170
|
+
raise RuntimeError(f"Failed to fetch OAuth token: {e}")
|
|
171
|
+
except (KeyError, ValueError) as e:
|
|
172
|
+
logger.error(f"Invalid token response format: {e}")
|
|
173
|
+
raise RuntimeError(f"Invalid token response format: {e}")
|
|
174
|
+
|
|
175
|
+
def extensions(self) -> Dict[str, str]:
|
|
176
|
+
"""
|
|
177
|
+
Return optional extensions to be sent with the SASL/OAUTHBEARER request.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
dict: Empty dict as no extensions are needed for basic client credentials flow
|
|
181
|
+
"""
|
|
182
|
+
return {}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
|
|
1
|
+
from mage_ai.data_preparation.models.constants import BlockType
|
|
4
2
|
from mage_ai.data_preparation.models.pipeline import Pipeline
|
|
5
3
|
from mage_ai.settings.repo import get_repo_path
|
|
6
4
|
from mage_ai.tests.api.endpoints.mixins import (
|
|
@@ -11,7 +9,6 @@ from mage_ai.tests.api.endpoints.mixins import (
|
|
|
11
9
|
build_list_endpoint_tests,
|
|
12
10
|
build_update_endpoint_tests,
|
|
13
11
|
)
|
|
14
|
-
from mage_ai.tests.shared.mixins import DBTMixin
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
def get_pipeline(self):
|
|
@@ -109,100 +106,3 @@ build_delete_endpoint_tests(
|
|
|
109
106
|
resource='block',
|
|
110
107
|
resource_parent='pipelines',
|
|
111
108
|
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class DBTBlockAPIEndpointTest(BaseAPIEndpointTest, DBTMixin):
|
|
115
|
-
pass
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def __assert_after_create(self):
|
|
119
|
-
pipeline = get_pipeline(self)
|
|
120
|
-
blocks = pipeline.blocks_by_uuid.values()
|
|
121
|
-
blocks_dbt = list(filter(
|
|
122
|
-
lambda x: x.type == BlockType.DBT and x.language == BlockLanguage.SQL,
|
|
123
|
-
blocks,
|
|
124
|
-
))
|
|
125
|
-
|
|
126
|
-
self.assertEqual(len(blocks), 5)
|
|
127
|
-
self.assertEqual(len(blocks_dbt), 1)
|
|
128
|
-
|
|
129
|
-
block = blocks_dbt[0]
|
|
130
|
-
self.assertEqual({
|
|
131
|
-
'dbt_project_name': 'dbt/test_project',
|
|
132
|
-
'file_path': 'dbt/test_project/models/example/my_first_dbt_model.sql',
|
|
133
|
-
'file_source': {
|
|
134
|
-
'path': 'dbt/test_project/models/example/my_first_dbt_model.sql',
|
|
135
|
-
'project_path': 'dbt/test_project',
|
|
136
|
-
},
|
|
137
|
-
}, block.configuration)
|
|
138
|
-
|
|
139
|
-
return True
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def __assert_after_create_yaml(self):
|
|
143
|
-
pipeline = get_pipeline(self)
|
|
144
|
-
blocks = pipeline.blocks_by_uuid.values()
|
|
145
|
-
blocks_dbt = list(filter(
|
|
146
|
-
lambda x: x.type == BlockType.DBT and x.language == BlockLanguage.YAML,
|
|
147
|
-
blocks,
|
|
148
|
-
))
|
|
149
|
-
|
|
150
|
-
self.assertEqual(len(blocks), 5)
|
|
151
|
-
self.assertEqual(len(blocks_dbt), 1)
|
|
152
|
-
|
|
153
|
-
block = blocks_dbt[0]
|
|
154
|
-
self.assertEqual({
|
|
155
|
-
'dbt_project_name': 'dbt/test_project',
|
|
156
|
-
'file_source': {
|
|
157
|
-
'path': 'dbts/dbt_yaml.yaml',
|
|
158
|
-
'project_path': 'dbt/test_project',
|
|
159
|
-
},
|
|
160
|
-
}, block.configuration)
|
|
161
|
-
|
|
162
|
-
return True
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
build_create_endpoint_tests(
|
|
166
|
-
DBTBlockAPIEndpointTest,
|
|
167
|
-
assert_after_create_count=__assert_after_create,
|
|
168
|
-
assert_before_create_count=lambda self: len(get_pipeline(self).blocks_by_uuid.values()) == 4,
|
|
169
|
-
build_payload=lambda self: dict(
|
|
170
|
-
name=self.faker.unique.name(),
|
|
171
|
-
type=BlockType.DBT,
|
|
172
|
-
language=BlockLanguage.SQL,
|
|
173
|
-
configuration=dict(
|
|
174
|
-
file_path=os.path.join(
|
|
175
|
-
os.path.basename(self.dbt_directory),
|
|
176
|
-
'test_project',
|
|
177
|
-
'models',
|
|
178
|
-
'example',
|
|
179
|
-
'my_first_dbt_model.sql',
|
|
180
|
-
),
|
|
181
|
-
),
|
|
182
|
-
),
|
|
183
|
-
get_resource_parent_id=lambda self: self.pipeline.uuid,
|
|
184
|
-
resource='block',
|
|
185
|
-
resource_parent='pipelines',
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
build_create_endpoint_tests(
|
|
190
|
-
DBTBlockAPIEndpointTest,
|
|
191
|
-
test_uuid='dbt_yaml',
|
|
192
|
-
assert_after_create_count=__assert_after_create_yaml,
|
|
193
|
-
assert_before_create_count=lambda self: len(get_pipeline(self).blocks_by_uuid.values()) == 4,
|
|
194
|
-
build_payload=lambda self: dict(
|
|
195
|
-
name='dbt_yaml',
|
|
196
|
-
type=BlockType.DBT,
|
|
197
|
-
language=BlockLanguage.YAML,
|
|
198
|
-
configuration=dict(
|
|
199
|
-
dbt_project_name=os.path.join(
|
|
200
|
-
os.path.basename(self.dbt_directory),
|
|
201
|
-
'test_project',
|
|
202
|
-
),
|
|
203
|
-
),
|
|
204
|
-
),
|
|
205
|
-
get_resource_parent_id=lambda self: self.pipeline.uuid,
|
|
206
|
-
resource='block',
|
|
207
|
-
resource_parent='pipelines',
|
|
208
|
-
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
-
from unittest.mock import patch
|
|
4
3
|
|
|
5
4
|
from mage_ai.authentication.permissions.constants import EntityName
|
|
6
5
|
from mage_ai.settings.models.configuration_option import ConfigurationType, OptionType
|
|
@@ -8,7 +7,7 @@ from mage_ai.tests.api.endpoints.mixins import (
|
|
|
8
7
|
BaseAPIEndpointTest,
|
|
9
8
|
build_list_endpoint_tests,
|
|
10
9
|
)
|
|
11
|
-
from mage_ai.tests.shared.mixins import DBTMixin
|
|
10
|
+
from mage_ai.tests.shared.mixins import DBTMixin
|
|
12
11
|
|
|
13
12
|
CURRENT_FILE_PATH = os.path.dirname(os.path.realpath(__file__))
|
|
14
13
|
|
|
@@ -51,49 +50,3 @@ build_list_endpoint_tests(
|
|
|
51
50
|
assert_after=__assert_after_list,
|
|
52
51
|
build_query=__build_query,
|
|
53
52
|
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@patch('mage_ai.settings.platform.utils.project_platform_activated', lambda: True)
|
|
57
|
-
@patch('mage_ai.settings.repo.project_platform_activated', lambda: True)
|
|
58
|
-
class ConfigurationOptionProjectPlatformAPIEndpointTest(
|
|
59
|
-
DBTMixin,
|
|
60
|
-
ProjectPlatformMixin,
|
|
61
|
-
BaseAPIEndpointTest,
|
|
62
|
-
):
|
|
63
|
-
pass
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def __assert_after_list2(self, result, **kwargs):
|
|
67
|
-
with open(os.path.join(
|
|
68
|
-
CURRENT_FILE_PATH,
|
|
69
|
-
'mocks',
|
|
70
|
-
'mock_dbt_configuration_options_project_platform.json',
|
|
71
|
-
)) as f:
|
|
72
|
-
self.assertEqual(
|
|
73
|
-
result,
|
|
74
|
-
json.loads(f.read()),
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
build_list_endpoint_tests(
|
|
79
|
-
ConfigurationOptionProjectPlatformAPIEndpointTest,
|
|
80
|
-
list_count=1,
|
|
81
|
-
get_resource_parent_id=lambda test_case: test_case.pipeline.uuid,
|
|
82
|
-
resource='configuration_option',
|
|
83
|
-
resource_parent='pipeline',
|
|
84
|
-
result_keys_to_compare=[
|
|
85
|
-
'configuration_type',
|
|
86
|
-
'metadata',
|
|
87
|
-
'option',
|
|
88
|
-
'option_type',
|
|
89
|
-
'resource_type',
|
|
90
|
-
'uuid',
|
|
91
|
-
],
|
|
92
|
-
assert_after=__assert_after_list2,
|
|
93
|
-
build_query=__build_query,
|
|
94
|
-
patch_function_settings=[
|
|
95
|
-
('mage_ai.settings.models.configuration_option.project_platform_activated', lambda: True),
|
|
96
|
-
('mage_ai.settings.platform.utils.project_platform_activated', lambda: True),
|
|
97
|
-
('mage_ai.settings.repo.project_platform_activated', lambda: True),
|
|
98
|
-
],
|
|
99
|
-
)
|