mage-ai 0.9.69__py3-none-any.whl → 0.9.71__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/ai/utils/xgboost.py +222 -0
- mage_ai/api/errors.py +37 -25
- mage_ai/api/operations/base.py +13 -1
- mage_ai/api/parsers/PipelineScheduleParser.py +1 -1
- mage_ai/api/policies/BackfillPolicy.py +1 -0
- mage_ai/api/policies/BlockOutputPolicy.py +40 -17
- mage_ai/api/policies/GlobalDataProductPolicy.py +91 -41
- mage_ai/api/policies/KernelPolicy.py +55 -32
- mage_ai/api/policies/KernelProcessPolicy.py +56 -0
- mage_ai/api/policies/OutputPolicy.py +73 -41
- mage_ai/api/policies/PipelinePolicy.py +206 -137
- mage_ai/api/policies/WorkspacePolicy.py +1 -0
- mage_ai/api/presenters/BackfillPresenter.py +1 -0
- mage_ai/api/presenters/BlockLayoutItemPresenter.py +9 -7
- mage_ai/api/presenters/BlockPresenter.py +1 -1
- mage_ai/api/presenters/GlobalDataProductPresenter.py +6 -1
- mage_ai/api/presenters/KernelPresenter.py +5 -26
- mage_ai/api/presenters/KernelProcessPresenter.py +28 -0
- mage_ai/api/presenters/PipelinePresenter.py +18 -5
- mage_ai/api/presenters/StatusPresenter.py +2 -0
- mage_ai/api/presenters/SyncPresenter.py +25 -0
- mage_ai/api/resources/AutocompleteItemResource.py +1 -1
- mage_ai/api/resources/BlockLayoutItemResource.py +90 -44
- mage_ai/api/resources/BlockOutputResource.py +42 -9
- mage_ai/api/resources/BlockResource.py +4 -3
- mage_ai/api/resources/BlockRunResource.py +27 -22
- mage_ai/api/resources/ClusterResource.py +4 -1
- mage_ai/api/resources/CustomTemplateResource.py +34 -14
- mage_ai/api/resources/DataProviderResource.py +1 -1
- mage_ai/api/resources/ExecutionStateResource.py +3 -1
- mage_ai/api/resources/FileContentResource.py +8 -2
- mage_ai/api/resources/FileResource.py +10 -4
- mage_ai/api/resources/FileVersionResource.py +3 -1
- mage_ai/api/resources/GitBranchResource.py +101 -31
- mage_ai/api/resources/GitCustomBranchResource.py +29 -1
- mage_ai/api/resources/GlobalDataProductResource.py +44 -7
- mage_ai/api/resources/GlobalHookResource.py +4 -1
- mage_ai/api/resources/IntegrationDestinationResource.py +6 -2
- mage_ai/api/resources/IntegrationSourceResource.py +8 -4
- mage_ai/api/resources/IntegrationSourceStreamResource.py +6 -2
- mage_ai/api/resources/KernelProcessResource.py +44 -0
- mage_ai/api/resources/KernelResource.py +25 -3
- mage_ai/api/resources/OauthResource.py +1 -1
- mage_ai/api/resources/OutputResource.py +33 -11
- mage_ai/api/resources/PageBlockLayoutResource.py +34 -23
- mage_ai/api/resources/PipelineInteractionResource.py +31 -15
- mage_ai/api/resources/PipelineResource.py +258 -125
- mage_ai/api/resources/PipelineRunResource.py +52 -7
- mage_ai/api/resources/PipelineScheduleResource.py +11 -2
- mage_ai/api/resources/PipelineTriggerResource.py +6 -1
- mage_ai/api/resources/ProjectResource.py +18 -7
- mage_ai/api/resources/PullRequestResource.py +6 -4
- mage_ai/api/resources/SecretResource.py +1 -1
- mage_ai/api/resources/SeedResource.py +8 -1
- mage_ai/api/resources/StatusResource.py +21 -6
- mage_ai/api/resources/SyncResource.py +6 -8
- mage_ai/api/resources/VariableResource.py +46 -26
- mage_ai/api/resources/VersionControlProjectResource.py +9 -2
- mage_ai/api/resources/WidgetResource.py +1 -1
- mage_ai/api/resources/WorkspaceResource.py +6 -5
- mage_ai/api/views.py +47 -40
- mage_ai/authentication/permissions/seed.py +16 -2
- mage_ai/authentication/providers/oidc.py +21 -1
- mage_ai/autocomplete/utils.py +13 -9
- mage_ai/cache/base.py +1 -1
- mage_ai/cache/block.py +18 -12
- mage_ai/cache/block_action_object/__init__.py +33 -5
- mage_ai/cache/file.py +22 -19
- mage_ai/cache/pipeline.py +18 -12
- mage_ai/cli/main.py +1 -0
- mage_ai/cluster_manager/aws/emr_cluster_manager.py +9 -5
- mage_ai/cluster_manager/config.py +2 -2
- mage_ai/cluster_manager/kubernetes/workload_manager.py +52 -1
- mage_ai/cluster_manager/manage.py +1 -1
- mage_ai/cluster_manager/workspace/base.py +7 -1
- mage_ai/cluster_manager/workspace/kubernetes.py +22 -1
- mage_ai/command_center/applications/factory.py +10 -7
- mage_ai/command_center/applications/utils.py +2 -2
- mage_ai/command_center/files/factory.py +17 -15
- mage_ai/command_center/presenters/text.py +1 -1
- mage_ai/command_center/utils.py +25 -13
- mage_ai/data/__init__.py +0 -0
- mage_ai/data/constants.py +45 -0
- mage_ai/data/models/__init__.py +0 -0
- mage_ai/data/models/base.py +119 -0
- mage_ai/data/models/constants.py +1 -0
- mage_ai/data/models/generator.py +115 -0
- mage_ai/data/models/manager.py +168 -0
- mage_ai/data/models/pyarrow/__init__.py +0 -0
- mage_ai/data/models/pyarrow/record_batch.py +55 -0
- mage_ai/data/models/pyarrow/shared.py +21 -0
- mage_ai/data/models/pyarrow/table.py +8 -0
- mage_ai/data/models/reader.py +103 -0
- mage_ai/data/models/utils.py +59 -0
- mage_ai/data/models/writer.py +91 -0
- mage_ai/data/tabular/__init__.py +0 -0
- mage_ai/data/tabular/constants.py +23 -0
- mage_ai/data/tabular/mocks.py +19 -0
- mage_ai/data/tabular/models.py +126 -0
- mage_ai/data/tabular/reader.py +602 -0
- mage_ai/data/tabular/utils.py +102 -0
- mage_ai/data/tabular/writer.py +266 -0
- mage_ai/data/variables/__init__.py +0 -0
- mage_ai/data/variables/wrapper.py +54 -0
- mage_ai/data_cleaner/analysis/charts.py +61 -39
- mage_ai/data_cleaner/column_types/column_type_detector.py +53 -31
- mage_ai/data_cleaner/estimators/encoders.py +5 -2
- mage_ai/data_integrations/utils/scheduler.py +16 -11
- mage_ai/data_preparation/decorators.py +1 -0
- mage_ai/data_preparation/executors/block_executor.py +237 -155
- mage_ai/data_preparation/executors/k8s_block_executor.py +30 -7
- mage_ai/data_preparation/executors/k8s_pipeline_executor.py +30 -7
- mage_ai/data_preparation/executors/streaming_pipeline_executor.py +2 -2
- mage_ai/data_preparation/git/__init__.py +77 -29
- mage_ai/data_preparation/git/api.py +69 -8
- mage_ai/data_preparation/git/utils.py +64 -34
- mage_ai/data_preparation/logging/logger_manager.py +4 -3
- mage_ai/data_preparation/models/block/__init__.py +1562 -879
- mage_ai/data_preparation/models/block/data_integration/mixins.py +4 -3
- mage_ai/data_preparation/models/block/dynamic/__init__.py +17 -6
- mage_ai/data_preparation/models/block/dynamic/child.py +41 -102
- mage_ai/data_preparation/models/block/dynamic/constants.py +1 -0
- mage_ai/data_preparation/models/block/dynamic/counter.py +296 -0
- mage_ai/data_preparation/models/block/dynamic/data.py +16 -0
- mage_ai/data_preparation/models/block/dynamic/factory.py +163 -0
- mage_ai/data_preparation/models/block/dynamic/models.py +19 -0
- mage_ai/data_preparation/models/block/dynamic/shared.py +92 -0
- mage_ai/data_preparation/models/block/dynamic/utils.py +295 -167
- mage_ai/data_preparation/models/block/dynamic/variables.py +384 -144
- mage_ai/data_preparation/models/block/dynamic/wrappers.py +77 -0
- mage_ai/data_preparation/models/block/extension/utils.py +10 -1
- mage_ai/data_preparation/models/block/global_data_product/__init__.py +35 -3
- mage_ai/data_preparation/models/block/integration/__init__.py +6 -2
- mage_ai/data_preparation/models/block/outputs.py +722 -0
- mage_ai/data_preparation/models/block/platform/mixins.py +7 -8
- mage_ai/data_preparation/models/block/r/__init__.py +56 -38
- mage_ai/data_preparation/models/block/remote/__init__.py +0 -0
- mage_ai/data_preparation/models/block/remote/models.py +58 -0
- mage_ai/data_preparation/models/block/settings/__init__.py +0 -0
- mage_ai/data_preparation/models/block/settings/dynamic/__init__.py +0 -0
- mage_ai/data_preparation/models/block/settings/dynamic/constants.py +7 -0
- mage_ai/data_preparation/models/block/settings/dynamic/mixins.py +118 -0
- mage_ai/data_preparation/models/block/settings/dynamic/models.py +31 -0
- mage_ai/data_preparation/models/block/settings/global_data_products/__init__.py +0 -0
- mage_ai/data_preparation/models/block/settings/global_data_products/mixins.py +20 -0
- mage_ai/data_preparation/models/block/settings/global_data_products/models.py +46 -0
- mage_ai/data_preparation/models/block/settings/variables/__init__.py +0 -0
- mage_ai/data_preparation/models/block/settings/variables/mixins.py +74 -0
- mage_ai/data_preparation/models/block/settings/variables/models.py +49 -0
- mage_ai/data_preparation/models/block/spark/mixins.py +2 -1
- mage_ai/data_preparation/models/block/sql/__init__.py +30 -5
- mage_ai/data_preparation/models/block/sql/utils/shared.py +21 -3
- mage_ai/data_preparation/models/block/utils.py +164 -69
- mage_ai/data_preparation/models/constants.py +21 -14
- mage_ai/data_preparation/models/custom_templates/custom_block_template.py +18 -13
- mage_ai/data_preparation/models/custom_templates/custom_pipeline_template.py +33 -16
- mage_ai/data_preparation/models/custom_templates/utils.py +1 -1
- mage_ai/data_preparation/models/file.py +41 -28
- mage_ai/data_preparation/models/global_data_product/__init__.py +100 -58
- mage_ai/data_preparation/models/global_hooks/models.py +1 -0
- mage_ai/data_preparation/models/interfaces.py +29 -0
- mage_ai/data_preparation/models/pipeline.py +374 -185
- mage_ai/data_preparation/models/pipelines/integration_pipeline.py +1 -2
- mage_ai/data_preparation/models/pipelines/seed.py +1 -1
- mage_ai/data_preparation/models/project/__init__.py +66 -18
- mage_ai/data_preparation/models/project/constants.py +2 -0
- mage_ai/data_preparation/models/triggers/__init__.py +124 -26
- mage_ai/data_preparation/models/utils.py +467 -17
- mage_ai/data_preparation/models/variable.py +1028 -137
- mage_ai/data_preparation/models/variables/__init__.py +0 -0
- mage_ai/data_preparation/models/variables/cache.py +149 -0
- mage_ai/data_preparation/models/variables/constants.py +72 -0
- mage_ai/data_preparation/models/variables/summarizer.py +336 -0
- mage_ai/data_preparation/models/variables/utils.py +77 -0
- mage_ai/data_preparation/models/widget/__init__.py +63 -41
- mage_ai/data_preparation/models/widget/charts.py +40 -27
- mage_ai/data_preparation/models/widget/constants.py +2 -0
- mage_ai/data_preparation/models/widget/utils.py +3 -3
- mage_ai/data_preparation/preferences.py +3 -3
- mage_ai/data_preparation/repo_manager.py +55 -21
- mage_ai/data_preparation/storage/base_storage.py +2 -2
- mage_ai/data_preparation/storage/gcs_storage.py +7 -4
- mage_ai/data_preparation/storage/local_storage.py +18 -9
- mage_ai/data_preparation/storage/s3_storage.py +5 -2
- mage_ai/data_preparation/templates/data_exporters/streaming/oracledb.yaml +8 -0
- mage_ai/data_preparation/variable_manager.py +281 -76
- mage_ai/io/base.py +3 -2
- mage_ai/io/bigquery.py +1 -0
- mage_ai/io/redshift.py +7 -5
- mage_ai/kernels/__init__.py +0 -0
- mage_ai/kernels/models.py +188 -0
- mage_ai/kernels/utils.py +169 -0
- mage_ai/orchestration/concurrency.py +6 -2
- mage_ai/orchestration/db/__init__.py +1 -0
- mage_ai/orchestration/db/migrations/versions/0227396a216c_add_userproject_table.py +38 -0
- mage_ai/orchestration/db/migrations/versions/42a14d6143f1_update_token_column_type.py +54 -0
- mage_ai/orchestration/db/models/dynamic/__init__.py +0 -0
- mage_ai/orchestration/db/models/dynamic/controller.py +67 -0
- mage_ai/orchestration/db/models/oauth.py +12 -18
- mage_ai/orchestration/db/models/projects.py +10 -0
- mage_ai/orchestration/db/models/schedules.py +225 -187
- mage_ai/orchestration/db/models/schedules_project_platform.py +18 -12
- mage_ai/orchestration/db/models/utils.py +46 -5
- mage_ai/orchestration/metrics/pipeline_run.py +8 -9
- mage_ai/orchestration/notification/sender.py +38 -15
- mage_ai/orchestration/pipeline_scheduler_original.py +64 -33
- mage_ai/orchestration/pipeline_scheduler_project_platform.py +1 -1
- mage_ai/orchestration/run_status_checker.py +11 -4
- mage_ai/orchestration/triggers/api.py +41 -2
- mage_ai/orchestration/triggers/global_data_product.py +9 -4
- mage_ai/orchestration/triggers/utils.py +10 -1
- mage_ai/orchestration/utils/resources.py +3 -0
- mage_ai/presenters/charts/data_sources/base.py +4 -2
- mage_ai/presenters/charts/data_sources/block.py +15 -9
- mage_ai/presenters/charts/data_sources/chart_code.py +8 -5
- mage_ai/presenters/charts/data_sources/constants.py +1 -0
- mage_ai/presenters/charts/data_sources/system_metrics.py +22 -0
- mage_ai/presenters/interactions/models.py +11 -7
- mage_ai/presenters/pages/loaders/pipelines.py +5 -3
- mage_ai/presenters/pages/models/page_components/pipeline_schedules.py +3 -1
- mage_ai/presenters/utils.py +2 -0
- mage_ai/server/api/blocks.py +2 -1
- mage_ai/server/api/downloads.py +9 -2
- mage_ai/server/api/runs.py +151 -0
- mage_ai/server/api/triggers.py +3 -1
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +8 -8
- mage_ai/server/frontend_dist/_next/static/UZLabyPgcxtZvp0O0EUUS/_buildManifest.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/1557-25a7d985d5564fd3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{3548-fa0792ddb88f4646.js → 3548-9d26185b3fb663b1.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/{3763-61b542dafdbf5754.js → 3763-40780c6d1e4b261d.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/5699-176f445e1313f001.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{main-77fe248a6fbd12d8.js → main-b99d4e30a88d9dc7.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-9fe2d9d07c94e968.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{overview-597b74828bf105db.js → overview-9f1ac4ec003884f3.js} +1 -1
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-3edc6270c5b0e962.js → frontend_dist/_next/static/chunks/pages/pipeline-runs-6d183f91a2ff6668.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7e737f6fc7e83e9b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-7acc7afc00df17c2.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-5f4c8128b2413fd8.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-1bdfda8edc9cf4a8.js → triggers-4612d15a65c35912.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js → frontend_dist/_next/static/chunks/pages/settings/platform/settings-319ddbabc239e91b.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{triggers-9cba3211434a8966.js → triggers-a599c6ac89be8c8d.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{webpack-d079359c241db804.js → webpack-ac7fdc472bedf682.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/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 +15 -15
- 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/version-control.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/404.html +8 -8
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1376-22de38b4ad008d8a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-25a7d985d5564fd3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1668-30b4619b9534519b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1799-c42db95a015689ee.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2996-2108b53b9d371d8d.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3548-fa0792ddb88f4646.js → 3548-9d26185b3fb663b1.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{3763-61b542dafdbf5754.js → 3763-40780c6d1e4b261d.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-129dd2a2448a2e36.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3958-bcdfa414ccfa1eb2.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4168-97fd1578d1a38315.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4982-fa5a238b139fbdd2.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-176f445e1313f001.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7162-7dd03f0f605de721.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7779-68d2b72a90c5f925.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-5446a8e43711e2f9.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8023-6c2f172f48dcb99b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-c351b8a735d73e0c.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{main-70b78159c2bb3fe1.js → main-384298e9133cec76.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-13a578bce3b7f30c.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{block-layout-14f952f66964022f.js → block-layout-7f4b735c67115df5.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-e7d48e6b0c3068ac.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-b943f31f050fc3a4.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{overview-597b74828bf105db.js → overview-9f1ac4ec003884f3.js} +1 -1
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipeline-runs-3edc6270c5b0e962.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-6d183f91a2ff6668.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7e737f6fc7e83e9b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-d94488e3f2eeef36.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-cc641a7fa8473796.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/{block-runs-a5c0362763a21fa8.js → block-runs-284309877f3c5a5a.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-26250e5335194ade.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-7acc7afc00df17c2.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-5f4c8128b2413fd8.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-4ebfc8e400315dda.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-e5e0150a256aadb3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-1bdfda8edc9cf4a8.js → triggers-4612d15a65c35912.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/{profile-3f0df3decc856ee9.js → profile-3ae43c932537b254.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-b603d7fe4b175256.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js → frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-319ddbabc239e91b.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-47b64ced27c24985.js → [...slug]-5c360f72e4498855.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-e5a4d3d815cec25d.js → permissions-fb29fa6c2bd90bb0.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-3b76fa959ffa09d3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-379e1ee292504842.js → [...slug]-3b787b42f1093b1f.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-0b83fbdd39e85f5b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-a1e6950974d643a8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-2af9afbe727d88aa.js → [...slug]-0aa019d87db8b0b8.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-a4db8710f703c729.js → users-88c694d19207f2ec.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{triggers-9cba3211434a8966.js → triggers-a599c6ac89be8c8d.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-31d0d50f7f30462b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-68c003fb6a175cd7.js → webpack-481689d9989710cd.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/kcptwoOU-JJJg6Vwpkfmx/_buildManifest.js +1 -0
- 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/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 +15 -15
- 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/version-control.html +6 -6
- mage_ai/server/kernel_output_parser.py +4 -1
- mage_ai/server/scheduler_manager.py +12 -1
- mage_ai/server/server.py +69 -42
- mage_ai/server/utils/custom_output.py +284 -0
- mage_ai/server/utils/execute_custom_code.py +245 -0
- mage_ai/server/utils/output_display.py +123 -289
- mage_ai/server/websocket_server.py +116 -69
- mage_ai/services/aws/ecs/ecs.py +1 -0
- mage_ai/services/k8s/config.py +27 -4
- mage_ai/services/k8s/job_manager.py +6 -1
- mage_ai/services/k8s/utils.py +97 -0
- mage_ai/services/ssh/aws/emr/utils.py +8 -8
- mage_ai/settings/keys/auth.py +1 -0
- mage_ai/settings/platform/__init__.py +159 -38
- mage_ai/settings/platform/constants.py +5 -0
- mage_ai/settings/platform/utils.py +53 -10
- mage_ai/settings/repo.py +26 -12
- mage_ai/settings/server.py +128 -37
- mage_ai/shared/array.py +24 -1
- mage_ai/shared/complex.py +45 -0
- mage_ai/shared/config.py +2 -1
- mage_ai/shared/custom_logger.py +11 -0
- mage_ai/shared/dates.py +10 -6
- mage_ai/shared/files.py +63 -8
- mage_ai/shared/hash.py +33 -9
- mage_ai/shared/io.py +9 -5
- mage_ai/shared/models.py +82 -24
- mage_ai/shared/outputs.py +87 -0
- mage_ai/shared/parsers.py +144 -13
- mage_ai/shared/path_fixer.py +11 -7
- mage_ai/shared/singletons/__init__.py +0 -0
- mage_ai/shared/singletons/base.py +47 -0
- mage_ai/shared/singletons/memory.py +38 -0
- mage_ai/shared/strings.py +34 -1
- mage_ai/shared/yaml.py +24 -0
- mage_ai/streaming/sinks/oracledb.py +57 -0
- mage_ai/streaming/sinks/sink_factory.py +4 -0
- mage_ai/system/__init__.py +0 -0
- mage_ai/system/constants.py +14 -0
- mage_ai/system/memory/__init__.py +0 -0
- mage_ai/system/memory/constants.py +1 -0
- mage_ai/system/memory/manager.py +174 -0
- mage_ai/system/memory/presenters.py +158 -0
- mage_ai/system/memory/process.py +216 -0
- mage_ai/system/memory/samples.py +13 -0
- mage_ai/system/memory/utils.py +656 -0
- mage_ai/system/memory/wrappers.py +177 -0
- mage_ai/system/models.py +58 -0
- mage_ai/system/storage/__init__.py +0 -0
- mage_ai/system/storage/utils.py +29 -0
- mage_ai/tests/api/endpoints/mixins.py +2 -2
- mage_ai/tests/api/endpoints/test_blocks.py +2 -1
- mage_ai/tests/api/endpoints/test_custom_designs.py +4 -4
- mage_ai/tests/api/endpoints/test_pipeline_runs.py +2 -2
- mage_ai/tests/api/endpoints/test_projects.py +2 -1
- mage_ai/tests/api/operations/base/mixins.py +1 -1
- mage_ai/tests/api/operations/base/test_base.py +27 -27
- mage_ai/tests/api/operations/base/test_base_with_user_authentication.py +27 -27
- mage_ai/tests/api/operations/base/test_base_with_user_permissions.py +23 -23
- mage_ai/tests/api/operations/test_syncs.py +6 -4
- mage_ai/tests/api/resources/test_pipeline_resource.py +11 -4
- mage_ai/tests/authentication/oauth/test_utils.py +1 -1
- mage_ai/tests/authentication/providers/test_oidc.py +59 -0
- mage_ai/tests/base_test.py +2 -2
- mage_ai/tests/data/__init__.py +0 -0
- mage_ai/tests/data/models/__init__.py +0 -0
- mage_ai/tests/data_preparation/executors/test_block_executor.py +23 -16
- mage_ai/tests/data_preparation/git/test_git.py +4 -1
- mage_ai/tests/data_preparation/models/block/dynamic/test_combos.py +305 -0
- mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +212 -0
- mage_ai/tests/data_preparation/models/block/dynamic/test_factory.py +360 -0
- mage_ai/tests/data_preparation/models/block/dynamic/test_variables.py +332 -0
- mage_ai/tests/data_preparation/models/block/hook/test_hook_block.py +2 -2
- mage_ai/tests/data_preparation/models/block/platform/test_mixins.py +1 -1
- mage_ai/tests/data_preparation/models/block/sql/utils/test_shared.py +26 -1
- mage_ai/tests/data_preparation/models/block/test_global_data_product.py +5 -2
- mage_ai/tests/data_preparation/models/custom_templates/test_utils.py +5 -4
- mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +3 -0
- mage_ai/tests/data_preparation/models/global_hooks/test_predicates.py +9 -3
- mage_ai/tests/data_preparation/models/test_block.py +115 -120
- mage_ai/tests/data_preparation/models/test_blocks_helper.py +114 -0
- mage_ai/tests/data_preparation/models/test_global_data_product.py +41 -24
- mage_ai/tests/data_preparation/models/test_pipeline.py +9 -6
- mage_ai/tests/data_preparation/models/test_project.py +4 -1
- mage_ai/tests/data_preparation/models/test_utils.py +80 -0
- mage_ai/tests/data_preparation/models/test_variable.py +242 -69
- mage_ai/tests/data_preparation/models/variables/__init__.py +0 -0
- mage_ai/tests/data_preparation/models/variables/test_summarizer.py +481 -0
- mage_ai/tests/data_preparation/storage/shared/__init__.py +0 -0
- mage_ai/tests/data_preparation/test_repo_manager.py +6 -7
- mage_ai/tests/data_preparation/test_variable_manager.py +57 -48
- mage_ai/tests/factory.py +64 -43
- mage_ai/tests/orchestration/db/models/test_schedules.py +3 -3
- mage_ai/tests/orchestration/db/models/test_schedules_dynamic_blocks.py +279 -0
- mage_ai/tests/orchestration/test_pipeline_scheduler.py +1 -0
- mage_ai/tests/orchestration/triggers/test_global_data_product.py +141 -138
- mage_ai/tests/orchestration/triggers/test_utils.py +3 -2
- mage_ai/tests/server/test_server.py +19 -0
- mage_ai/tests/services/k8s/test_job_manager.py +27 -6
- mage_ai/tests/streaming/sinks/test_oracledb.py +38 -0
- mage_ai/tests/test_shared.py +61 -0
- mage_ai/usage_statistics/logger.py +7 -2
- mage_ai/utils/code.py +33 -19
- mage_ai/version_control/branch/utils.py +2 -1
- mage_ai/version_control/models.py +3 -2
- {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/METADATA +6 -3
- {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/RECORD +555 -454
- mage_ai/data_preparation/models/global_data_product/constants.py +0 -6
- mage_ai/server/frontend_dist/_next/static/_krrrgup_C-dPOpX36S8I/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/4783-422429203610c318.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/KLL5mirre9d7_ZeEpaw3s/_buildManifest.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2631-b9f9bea3f1cf906d.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3782-ef4cd4f0b52072d0.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4783-422429203610c318.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/635-0d6b7c8804bcd2dc.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7022-0d52dd8868621fb0.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8095-bdce03896ef9639a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8146-6bed4e7401e067e6.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9265-d2a1aaec75ec69b8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9832-67896490f6e8a014.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/[...slug]-591abd392dc50ed4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products-78e8e88f2a757a18.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-95ffcd3e2b27e567.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-1ed9045b2f1dfd65.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/[run]-1417ad1c821d720a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles-36fa165a48af586b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-8b793b3b696a2cd3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
- mage_ai/shared/memory.py +0 -90
- mage_ai/tests/data_preparation/models/block/dynamic/test_dynamic_helpers.py +0 -48
- /mage_ai/{tests/data_preparation/shared → ai/utils}/__init__.py +0 -0
- /mage_ai/server/frontend_dist/_next/static/{_krrrgup_C-dPOpX36S8I → UZLabyPgcxtZvp0O0EUUS}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{KLL5mirre9d7_ZeEpaw3s → kcptwoOU-JJJg6Vwpkfmx}/_ssgManifest.js +0 -0
- /mage_ai/tests/data_preparation/{shared → storage/shared}/test_secrets.py +0 -0
- {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.69.dist-info → mage_ai-0.9.71.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import functools
|
|
3
|
+
import io
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import threading
|
|
8
|
+
import time
|
|
9
|
+
from collections import deque
|
|
10
|
+
from collections.abc import Container, Iterable, Mapping
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from logging import Logger
|
|
13
|
+
from sys import getsizeof
|
|
14
|
+
from typing import Any, Callable, Dict, Optional, Tuple
|
|
15
|
+
|
|
16
|
+
import joblib
|
|
17
|
+
import pandas as pd
|
|
18
|
+
import psutil
|
|
19
|
+
import pyarrow.parquet as pq
|
|
20
|
+
from memory_profiler import memory_usage
|
|
21
|
+
|
|
22
|
+
from mage_ai.data_preparation.logging.logger import DictLogger
|
|
23
|
+
from mage_ai.settings.repo import get_variables_dir
|
|
24
|
+
from mage_ai.system.constants import METRICS_DIRECTORY, SYSTEM_DIRECTORY, LogType
|
|
25
|
+
from mage_ai.system.models import MemoryUsage, ResourceUsage
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_log_directory(
|
|
29
|
+
scope_uuid: str,
|
|
30
|
+
repo_path: Optional[str] = None,
|
|
31
|
+
) -> str:
|
|
32
|
+
"""
|
|
33
|
+
/root/.mage_data/[project]
|
|
34
|
+
/system/metrics
|
|
35
|
+
/pipelines/[pipeline_uuid]/[block_uuid]
|
|
36
|
+
"""
|
|
37
|
+
variables_dir = get_variables_dir(repo_path=repo_path, root_project=False)
|
|
38
|
+
|
|
39
|
+
return os.path.join(
|
|
40
|
+
variables_dir,
|
|
41
|
+
SYSTEM_DIRECTORY,
|
|
42
|
+
METRICS_DIRECTORY,
|
|
43
|
+
scope_uuid, # pipelines/[pipeline_uuid]/[block_uuid]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def log_or_print(
|
|
48
|
+
log_message: str,
|
|
49
|
+
logger: Optional[Logger] = None,
|
|
50
|
+
logging_tags: Optional[Dict] = None,
|
|
51
|
+
message_prefix: Optional[str] = None,
|
|
52
|
+
):
|
|
53
|
+
if message_prefix:
|
|
54
|
+
log_message = f'{message_prefix} {log_message}'
|
|
55
|
+
if logger:
|
|
56
|
+
if isinstance(logger, DictLogger):
|
|
57
|
+
logger.info(log_message, tags=logging_tags)
|
|
58
|
+
else:
|
|
59
|
+
logger.info(log_message)
|
|
60
|
+
if logging_tags:
|
|
61
|
+
logger.info(json.dumps(logging_tags, indent=2))
|
|
62
|
+
else:
|
|
63
|
+
print(log_message)
|
|
64
|
+
if logging_tags:
|
|
65
|
+
print(json.dumps(logging_tags, indent=2))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_memory_usage(
|
|
69
|
+
log: bool = True,
|
|
70
|
+
logger: Optional[Logger] = None,
|
|
71
|
+
logging_tags: Optional[Dict] = None,
|
|
72
|
+
message_prefix: Optional[str] = None,
|
|
73
|
+
wrapped_function: Optional[Callable] = None,
|
|
74
|
+
) -> Tuple[Optional[Any], ResourceUsage]:
|
|
75
|
+
process = psutil.Process(os.getpid())
|
|
76
|
+
info_start = process.memory_info()
|
|
77
|
+
value_start = info_start.rss
|
|
78
|
+
memory = [
|
|
79
|
+
MemoryUsage.load(
|
|
80
|
+
pageins=getattr(info_start, 'pageins', 0),
|
|
81
|
+
pfaults=getattr(info_start, 'pfaults', 0),
|
|
82
|
+
rss=value_start,
|
|
83
|
+
timestamp=int(datetime.utcnow().timestamp() * 1000), # in milliseconds
|
|
84
|
+
vms=info_start.vms,
|
|
85
|
+
),
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
# if log or logger:
|
|
89
|
+
# message = f'Starting memory: {(value_start / (1024 * 1024)):.3f}MB'
|
|
90
|
+
# log_or_print(
|
|
91
|
+
# message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
92
|
+
# )
|
|
93
|
+
|
|
94
|
+
if wrapped_function:
|
|
95
|
+
result = wrapped_function()
|
|
96
|
+
|
|
97
|
+
info_end = process.memory_info()
|
|
98
|
+
value_end = info_end.rss
|
|
99
|
+
memory.append(
|
|
100
|
+
MemoryUsage.load(
|
|
101
|
+
pageins=getattr(info_end, 'pageins', 0),
|
|
102
|
+
pfaults=getattr(info_end, 'pfaults', 0),
|
|
103
|
+
rss=value_end,
|
|
104
|
+
timestamp=int(datetime.utcnow().timestamp() * 1000), # in milliseconds
|
|
105
|
+
vms=info_end.vms,
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if log or logger:
|
|
110
|
+
# message = f'Ending memory: {(value_end / (1024 * 1024)):.3f}MB'
|
|
111
|
+
# log_or_print(
|
|
112
|
+
# message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
113
|
+
# )
|
|
114
|
+
message = f'Memory: {((value_end - value_start) / (1024 * 1024)):.3f}MB'
|
|
115
|
+
log_or_print(
|
|
116
|
+
message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
117
|
+
)
|
|
118
|
+
# message = (
|
|
119
|
+
# f'Time elapsed: {round((memory[-1].timestamp - memory[0].timestamp) / 1000)} '
|
|
120
|
+
# 'seconds'
|
|
121
|
+
# )
|
|
122
|
+
# log_or_print(
|
|
123
|
+
# message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
124
|
+
# )
|
|
125
|
+
|
|
126
|
+
return result, ResourceUsage.load(memory=memory)
|
|
127
|
+
|
|
128
|
+
return None, ResourceUsage.load(memory=memory)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
async def get_memory_usage_async(
|
|
132
|
+
log: bool = True,
|
|
133
|
+
logger: Optional[Logger] = None,
|
|
134
|
+
logging_tags: Optional[Dict] = None,
|
|
135
|
+
message_prefix: Optional[str] = None,
|
|
136
|
+
wrapped_function: Optional[Callable] = None,
|
|
137
|
+
) -> Tuple[Optional[Any], ResourceUsage]:
|
|
138
|
+
process = psutil.Process(os.getpid())
|
|
139
|
+
info_start = process.memory_info()
|
|
140
|
+
value_start = info_start.rss
|
|
141
|
+
memory = [
|
|
142
|
+
MemoryUsage.load(
|
|
143
|
+
pageins=getattr(info_start, 'pageins', 0),
|
|
144
|
+
pfaults=getattr(info_start, 'pfaults', 0),
|
|
145
|
+
rss=value_start,
|
|
146
|
+
timestamp=int(datetime.utcnow().timestamp() * 1000), # in milliseconds
|
|
147
|
+
vms=info_start.vms,
|
|
148
|
+
),
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
# if log or logger:
|
|
152
|
+
# message = f'Starting memory: {(value_start / (1024 * 1024)):.3f}MB'
|
|
153
|
+
# log_or_print(
|
|
154
|
+
# message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
155
|
+
# )
|
|
156
|
+
|
|
157
|
+
if wrapped_function:
|
|
158
|
+
result = await wrapped_function()
|
|
159
|
+
|
|
160
|
+
info_end = process.memory_info()
|
|
161
|
+
value_end = info_end.rss
|
|
162
|
+
memory.append(
|
|
163
|
+
MemoryUsage.load(
|
|
164
|
+
pageins=getattr(info_end, 'pageins', 0),
|
|
165
|
+
pfaults=getattr(info_end, 'pfaults', 0),
|
|
166
|
+
rss=value_end,
|
|
167
|
+
timestamp=int(datetime.utcnow().timestamp() * 1000), # in milliseconds
|
|
168
|
+
vms=info_end.vms,
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if log or logger:
|
|
173
|
+
# message = f'Ending memory: {(value_end / (1024 * 1024)):.3f}MB'
|
|
174
|
+
# log_or_print(
|
|
175
|
+
# message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
176
|
+
# )
|
|
177
|
+
message = f'Memory: {((value_end - value_start) / (1024 * 1024)):.3f}MB'
|
|
178
|
+
log_or_print(
|
|
179
|
+
message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
180
|
+
)
|
|
181
|
+
# message = (
|
|
182
|
+
# f'Time elapsed: {round((memory[-1].timestamp - memory[0].timestamp) / 1000)} '
|
|
183
|
+
# 'seconds'
|
|
184
|
+
# )
|
|
185
|
+
# log_or_print(
|
|
186
|
+
# message, logger=logger, logging_tags=logging_tags, message_prefix=message_prefix
|
|
187
|
+
# )
|
|
188
|
+
|
|
189
|
+
return result, ResourceUsage.load(memory=memory)
|
|
190
|
+
|
|
191
|
+
return None, ResourceUsage.load(memory=memory)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def estimate_parquet_memory_usage(file_path: str) -> float:
|
|
195
|
+
"""
|
|
196
|
+
Adjusted function to estimate the memory usage of a Parquet file when loaded.
|
|
197
|
+
It utilizes PyArrow to access the metadata for a more accurate estimation.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
file_path (str) - The path to the Parquet file.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
float: The estimated memory usage in bytes.
|
|
204
|
+
"""
|
|
205
|
+
if not file_path.endswith('.parquet'):
|
|
206
|
+
raise ValueError('Not a Parquet file.')
|
|
207
|
+
if not os.path.isfile(file_path):
|
|
208
|
+
raise FileNotFoundError(f'File {file_path} not found.')
|
|
209
|
+
|
|
210
|
+
# Use PyArrow to read metadata
|
|
211
|
+
parquet_file = pq.ParquetFile(file_path)
|
|
212
|
+
metadata = parquet_file.metadata
|
|
213
|
+
|
|
214
|
+
# The actual memory usage can vary significantly based on the data types
|
|
215
|
+
# and compression used in the file. Loop through all row groups to sum their uncompressed sizes.
|
|
216
|
+
total_uncompressed_size = sum(
|
|
217
|
+
metadata.row_group(i).total_byte_size for i in range(metadata.num_row_groups)
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# This gives you the total uncompressed size of the data in the Parquet file,
|
|
221
|
+
# which is a better approximation of its in-memory size than disk size,
|
|
222
|
+
# especially as Parquet files are often compressed.
|
|
223
|
+
return total_uncompressed_size
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def estimate_file_memory_usage(file_path: str) -> Dict[str, float]:
|
|
227
|
+
"""
|
|
228
|
+
Estimates the amount of memory a file will take up when loaded into memory.
|
|
229
|
+
This is a rough estimation and actual memory usage can vary.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
file_path (str): The path to the file on disk.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
dict: A dictionary containing the size on disk, and estimated memory usage in bytes.
|
|
236
|
+
"""
|
|
237
|
+
if not os.path.isfile(file_path):
|
|
238
|
+
return {}
|
|
239
|
+
|
|
240
|
+
file_size = os.path.getsize(file_path) # Size in bytes
|
|
241
|
+
|
|
242
|
+
# Assuming the file will roughly take the same amount of memory in bytes as its size on disk.
|
|
243
|
+
# This assumption holds for binary files but can vary for text files depending on the encoding,
|
|
244
|
+
# and how the data is processed or represented in memory.
|
|
245
|
+
|
|
246
|
+
# Default assumption: memory usage is equal to file size
|
|
247
|
+
estimated_memory_usage = file_size
|
|
248
|
+
|
|
249
|
+
# Estimate memory usage based on file type
|
|
250
|
+
if file_path.endswith('.txt'):
|
|
251
|
+
# Assume each character takes 1 byte
|
|
252
|
+
estimated_memory_usage = file_size
|
|
253
|
+
elif file_path.endswith('.csv'):
|
|
254
|
+
# Assume each character takes 1 byte and add overhead for data structures
|
|
255
|
+
estimated_memory_usage = file_size * 1.2
|
|
256
|
+
elif file_path.endswith('.json'):
|
|
257
|
+
# Assume each character takes 1 byte and add overhead for data structures
|
|
258
|
+
estimated_memory_usage = file_size * 1.5
|
|
259
|
+
elif file_path.endswith('.parquet'):
|
|
260
|
+
# Estimate memory usage based on the Parquet file format
|
|
261
|
+
estimated_memory_usage = estimate_parquet_memory_usage(file_path)
|
|
262
|
+
elif file_path.endswith('.ubj'):
|
|
263
|
+
# Assuming UBJ files expand less than JSON due to their efficient binary format
|
|
264
|
+
# This is a heuristic and may need adjustment based on actual data
|
|
265
|
+
estimated_memory_usage *= 2 # Assuming some expansion in memory
|
|
266
|
+
elif file_path.endswith('.joblib'):
|
|
267
|
+
# Joblib files are used for serializing Python objects. The memory usage
|
|
268
|
+
# Could be quite different from the file size depending on the object.
|
|
269
|
+
# Using a heuristic here, but for accurate measurements, deserialization might be necessary.
|
|
270
|
+
estimated_memory_usage *= 4 # Assuming significant expansion due to decompression
|
|
271
|
+
|
|
272
|
+
# If you want to add specific estimates for different file types
|
|
273
|
+
# (e.g., images, serialized objects),
|
|
274
|
+
# you could extend this function with more logic.
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
'size_on_disk_bytes': file_size,
|
|
278
|
+
'estimated_memory_usage_bytes': estimated_memory_usage,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def deep_getsizeof(o, ids) -> float:
|
|
283
|
+
"""Find the memory footprint of a Python object, including the contents of containers."""
|
|
284
|
+
if id(o) in ids:
|
|
285
|
+
return 0
|
|
286
|
+
|
|
287
|
+
ids.add(id(o))
|
|
288
|
+
size = getsizeof(o)
|
|
289
|
+
|
|
290
|
+
if isinstance(o, str) or isinstance(o, bytes):
|
|
291
|
+
return size
|
|
292
|
+
|
|
293
|
+
if isinstance(o, Mapping):
|
|
294
|
+
size += sum((deep_getsizeof(k, ids) + deep_getsizeof(v, ids) for k, v in o.items()))
|
|
295
|
+
|
|
296
|
+
elif isinstance(o, Container):
|
|
297
|
+
size += sum((deep_getsizeof(i, ids) for i in o))
|
|
298
|
+
|
|
299
|
+
return size
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def estimate_object_memory(obj) -> float:
|
|
303
|
+
"""Estimate the memory usage of an object including its contents."""
|
|
304
|
+
return deep_getsizeof(obj, set())
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def estimate_memory_usage(obj) -> float:
|
|
308
|
+
"""
|
|
309
|
+
Estimates the memory usage of various object instances in Python.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
- obj: the object instance for which to estimate memory usage.
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
- The estimated memory size in bytes.
|
|
316
|
+
"""
|
|
317
|
+
if isinstance(obj, dict):
|
|
318
|
+
return sum((getsizeof(key) + getsizeof(value) for key, value in obj.items())) + getsizeof(
|
|
319
|
+
obj
|
|
320
|
+
)
|
|
321
|
+
elif isinstance(obj, Iterable) and not isinstance(obj, str):
|
|
322
|
+
return sum((getsizeof(item) for item in obj)) + getsizeof(obj)
|
|
323
|
+
try:
|
|
324
|
+
# Use specialized methods for complex types if available.
|
|
325
|
+
obj_type = type(obj).__name__.lower()
|
|
326
|
+
if obj_type == 'dataframe':
|
|
327
|
+
return obj.memory_usage(deep=True).sum()
|
|
328
|
+
elif obj_type == 'geodataframe':
|
|
329
|
+
return obj.memory_usage(deep=True).sum() + getsizeof(obj.geometry)
|
|
330
|
+
elif obj_type in ['series', 'series_pandas']:
|
|
331
|
+
return obj.memory_usage(deep=True)
|
|
332
|
+
elif obj_type == 'matrix_sparse':
|
|
333
|
+
return getsizeof(obj.data) + getsizeof(obj.indices) + getsizeof(obj.indptr)
|
|
334
|
+
elif obj_type in ['model_sklearn', 'model_xgboost']:
|
|
335
|
+
import joblib
|
|
336
|
+
|
|
337
|
+
return len(joblib.dumps(obj))
|
|
338
|
+
elif obj_type == 'polars_dataframe':
|
|
339
|
+
return obj.heap_size()
|
|
340
|
+
elif obj_type == 'spark_dataframe':
|
|
341
|
+
# Spark DataFrames are distributed, it's tricky to estimate accurately without scanning.
|
|
342
|
+
# This would just be a placeholder as actual memory usage requires cluster state.
|
|
343
|
+
return 0
|
|
344
|
+
elif obj_type == 'custom_object':
|
|
345
|
+
# A more complex heuristic might be necessary here.
|
|
346
|
+
return getsizeof(obj) # Likely an underestimate for complex custom objects.
|
|
347
|
+
else:
|
|
348
|
+
return getsizeof(obj)
|
|
349
|
+
except AttributeError:
|
|
350
|
+
# Fallback for objects that don't fit handled types or lack memory usage methods
|
|
351
|
+
return getsizeof(obj)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def enhanced_estimate_memory_usage(obj) -> float:
|
|
355
|
+
"""
|
|
356
|
+
Enhanced memory usage estimation for a broad spectrum of Python object types,
|
|
357
|
+
focusing on native data structures, pandas objects, and handling for complex or
|
|
358
|
+
custom objects that might be serialized (e.g., machine learning models).
|
|
359
|
+
"""
|
|
360
|
+
visited_ids = set()
|
|
361
|
+
queue = deque([obj])
|
|
362
|
+
total_size = 0
|
|
363
|
+
|
|
364
|
+
while queue:
|
|
365
|
+
current_obj = queue.popleft()
|
|
366
|
+
obj_id = id(current_obj)
|
|
367
|
+
if obj_id in visited_ids:
|
|
368
|
+
continue
|
|
369
|
+
|
|
370
|
+
visited_ids.add(obj_id)
|
|
371
|
+
|
|
372
|
+
# Initially, add the object's own size
|
|
373
|
+
total_size += getsizeof(current_obj)
|
|
374
|
+
|
|
375
|
+
# Extend the queue with object contents, if applicable
|
|
376
|
+
if isinstance(current_obj, dict):
|
|
377
|
+
queue.extend(current_obj.keys())
|
|
378
|
+
queue.extend(current_obj.values())
|
|
379
|
+
elif isinstance(current_obj, (list, tuple, set, frozenset)):
|
|
380
|
+
queue.extend(current_obj)
|
|
381
|
+
elif hasattr(current_obj, '__dict__'):
|
|
382
|
+
queue.append(current_obj.__dict__)
|
|
383
|
+
elif hasattr(current_obj, '__slots__'):
|
|
384
|
+
queue.extend(
|
|
385
|
+
getattr(
|
|
386
|
+
current_obj,
|
|
387
|
+
slot,
|
|
388
|
+
)
|
|
389
|
+
for slot in current_obj.__slots__
|
|
390
|
+
if hasattr(current_obj, slot)
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
# Special handling for objects that support direct memory usage estimation
|
|
394
|
+
if isinstance(current_obj, pd.DataFrame):
|
|
395
|
+
# For DataFrame, use pandas' `memory_usage(deep=True)` method
|
|
396
|
+
total_size += current_obj.memory_usage(deep=True).sum()
|
|
397
|
+
elif isinstance(current_obj, (pd.Series, pd.Index)):
|
|
398
|
+
# Ditto for Series and Index
|
|
399
|
+
total_size += current_obj.memory_usage(deep=True)
|
|
400
|
+
|
|
401
|
+
# Handle serialization-based estimation for complex objects
|
|
402
|
+
elif type(current_obj).__name__ in [
|
|
403
|
+
'Booster',
|
|
404
|
+
'XGBModel',
|
|
405
|
+
]: # Example for ML models
|
|
406
|
+
# Serialize the object into a bytes buffer and measure its size
|
|
407
|
+
buffer = io.BytesIO()
|
|
408
|
+
joblib.dump(current_obj, buffer)
|
|
409
|
+
total_size += buffer.tell()
|
|
410
|
+
|
|
411
|
+
return total_size
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def get_csr_matrix_memory_usage(csr):
|
|
415
|
+
"""
|
|
416
|
+
Estimate memory usage of a csr_matrix.
|
|
417
|
+
|
|
418
|
+
Parameters:
|
|
419
|
+
- csr: The csr_matrix whose memory usage is to be estimated.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
- The estimated memory usage in bytes.
|
|
423
|
+
"""
|
|
424
|
+
base_size = sys.getsizeof(csr)
|
|
425
|
+
data_size = csr.data.nbytes
|
|
426
|
+
indices_size = csr.indices.nbytes
|
|
427
|
+
indptr_size = csr.indptr.nbytes
|
|
428
|
+
|
|
429
|
+
total_size = base_size + data_size + indices_size + indptr_size
|
|
430
|
+
return total_size
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def print_nice_lines(data, column_padding=2):
|
|
434
|
+
"""
|
|
435
|
+
Prints a list of dictionaries (data) as a nicely formatted table.
|
|
436
|
+
Args:
|
|
437
|
+
data (list of dict): The table data, where each dictionary represents a row.
|
|
438
|
+
column_padding (int): The padding spaces between columns for readability.
|
|
439
|
+
"""
|
|
440
|
+
|
|
441
|
+
if not data:
|
|
442
|
+
print('No data to display.')
|
|
443
|
+
return
|
|
444
|
+
|
|
445
|
+
# Extract headers
|
|
446
|
+
headers = data[0].keys()
|
|
447
|
+
|
|
448
|
+
# Find the maximum length of the value for each header for alignment
|
|
449
|
+
column_widths = {header: len(header) for header in headers}
|
|
450
|
+
for row in data:
|
|
451
|
+
for header in headers:
|
|
452
|
+
column_widths[header] = max(column_widths[header], len(str(row.get(header, ''))))
|
|
453
|
+
|
|
454
|
+
# Create a format string for padding the columns
|
|
455
|
+
row_format = ''.join([f'{{:<{column_widths[header] + column_padding}}}' for header in headers])
|
|
456
|
+
|
|
457
|
+
# Print headers
|
|
458
|
+
print(row_format.format(*headers))
|
|
459
|
+
|
|
460
|
+
# Print rows
|
|
461
|
+
for row in data:
|
|
462
|
+
print(row_format.format(*[row.get(header, '') for header in headers]))
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def combined_memory_util(runs=1, return_output=False):
|
|
466
|
+
"""
|
|
467
|
+
Decorator to measure both memory usage in GB and execution time of `func`,
|
|
468
|
+
running the function `runs` times and averaging the results.
|
|
469
|
+
Args:
|
|
470
|
+
runs (int): The number of times to run the decorated function.
|
|
471
|
+
"""
|
|
472
|
+
|
|
473
|
+
def decorator(func, return_output=return_output):
|
|
474
|
+
@functools.wraps(func)
|
|
475
|
+
def wrapper(*args, return_output=return_output, **kwargs):
|
|
476
|
+
times = []
|
|
477
|
+
mem_starts_ps = []
|
|
478
|
+
mem_starts_mp = []
|
|
479
|
+
mem_ends_ps = []
|
|
480
|
+
mem_ends_mp = []
|
|
481
|
+
mem_diff_ps = []
|
|
482
|
+
mem_diff_mp = []
|
|
483
|
+
result = None
|
|
484
|
+
|
|
485
|
+
for idx in range(runs):
|
|
486
|
+
print(f'Run {idx + 1}/{runs}...')
|
|
487
|
+
|
|
488
|
+
# Measure initial memory using psutil (in bytes)
|
|
489
|
+
process = psutil.Process(os.getpid())
|
|
490
|
+
mem_before_psutil = process.memory_info().rss
|
|
491
|
+
mem_starts_ps.append(mem_before_psutil)
|
|
492
|
+
|
|
493
|
+
# Measure initial memory using memory_profiler (in bytes)
|
|
494
|
+
mem_usage_before = (
|
|
495
|
+
memory_usage(-1, interval=0.1, timeout=1, max_usage=True) * 1024 * 1024
|
|
496
|
+
)
|
|
497
|
+
mem_starts_mp.append(mem_usage_before)
|
|
498
|
+
|
|
499
|
+
# Start timing
|
|
500
|
+
start_time = time.time()
|
|
501
|
+
|
|
502
|
+
if return_output and idx == runs - 1:
|
|
503
|
+
result = func(*args, **kwargs)
|
|
504
|
+
else:
|
|
505
|
+
func(*args, **kwargs)
|
|
506
|
+
|
|
507
|
+
# End timing
|
|
508
|
+
elapsed_time = time.time() - start_time
|
|
509
|
+
times.append(elapsed_time)
|
|
510
|
+
|
|
511
|
+
# Measure memory after execution using psutil (in bytes)
|
|
512
|
+
mem_after_psutil = process.memory_info().rss
|
|
513
|
+
mem_ends_ps.append(mem_after_psutil)
|
|
514
|
+
|
|
515
|
+
# Measure memory after execution using memory_profiler (in bytes)
|
|
516
|
+
mem_usage_after = (
|
|
517
|
+
memory_usage(-1, interval=0.1, timeout=1, max_usage=True) * 1024 * 1024
|
|
518
|
+
)
|
|
519
|
+
mem_ends_mp.append(mem_usage_after)
|
|
520
|
+
|
|
521
|
+
# Update the total memory usage differences
|
|
522
|
+
mem_diff_ps.append(mem_after_psutil - mem_before_psutil)
|
|
523
|
+
mem_diff_mp.append(mem_usage_after - mem_usage_before)
|
|
524
|
+
|
|
525
|
+
# Calculate averages
|
|
526
|
+
stats = [
|
|
527
|
+
sum(arr) / runs
|
|
528
|
+
for arr in [
|
|
529
|
+
mem_starts_mp,
|
|
530
|
+
mem_ends_mp,
|
|
531
|
+
mem_diff_mp,
|
|
532
|
+
mem_starts_ps,
|
|
533
|
+
mem_ends_ps,
|
|
534
|
+
mem_diff_ps,
|
|
535
|
+
]
|
|
536
|
+
]
|
|
537
|
+
|
|
538
|
+
# Print average results
|
|
539
|
+
factor = 1 / (1024**3)
|
|
540
|
+
data = [
|
|
541
|
+
{
|
|
542
|
+
' ': 'mp',
|
|
543
|
+
'Str': f'{(stats[0] * factor):.3f} GB',
|
|
544
|
+
'End': f'{(stats[1] * factor):.3f} GB',
|
|
545
|
+
'Use': f'{(stats[2] * factor):.3f} GB',
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
' ': 'ps',
|
|
549
|
+
'Str': f'{(stats[3] * factor):.3f} GB',
|
|
550
|
+
'End': f'{(stats[4] * factor):.3f} GB',
|
|
551
|
+
'Use': f'{(stats[5] * factor):.3f} GB',
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
' ': ' ',
|
|
555
|
+
'Str': '',
|
|
556
|
+
'End': '',
|
|
557
|
+
'Use': f'{(sum(times) / runs):.3f} secs',
|
|
558
|
+
},
|
|
559
|
+
]
|
|
560
|
+
|
|
561
|
+
print_nice_lines(data)
|
|
562
|
+
|
|
563
|
+
return result
|
|
564
|
+
|
|
565
|
+
return wrapper
|
|
566
|
+
|
|
567
|
+
return decorator
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def current_memory_usage() -> int:
|
|
571
|
+
"""
|
|
572
|
+
Returns the current memory usage of the process in bytes.
|
|
573
|
+
|
|
574
|
+
Original value is MB, but we convert it to bytes.
|
|
575
|
+
"""
|
|
576
|
+
return int(memory_usage(-1)[0] * 1024**2)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def format_metadata_message(metadata: Dict) -> str:
|
|
580
|
+
return ' '.join([f'{k}={v}' for k, v in metadata.items() if v is not None])
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def format_log_message(
|
|
584
|
+
log_type: Optional[LogType] = None,
|
|
585
|
+
message: Optional[Any] = None,
|
|
586
|
+
metadata: Optional[Dict] = None,
|
|
587
|
+
) -> str:
|
|
588
|
+
log_type = log_type or LogType.MEMORY
|
|
589
|
+
timestamp = round(datetime.utcnow().timestamp())
|
|
590
|
+
metadata = metadata or {}
|
|
591
|
+
|
|
592
|
+
msg = f'[{timestamp}][{log_type.value}]'
|
|
593
|
+
if message:
|
|
594
|
+
msg += f' {message}'
|
|
595
|
+
|
|
596
|
+
if metadata:
|
|
597
|
+
msg += f' {format_metadata_message(metadata)}'
|
|
598
|
+
|
|
599
|
+
return f'{msg}\n'
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def monitor_memory_usage(
|
|
603
|
+
callback: Optional[Callable[[float], Any]],
|
|
604
|
+
interval_seconds: float = 1.0,
|
|
605
|
+
):
|
|
606
|
+
"""
|
|
607
|
+
Monitor and logs memory usage periodically to the same log file.
|
|
608
|
+
"""
|
|
609
|
+
|
|
610
|
+
def monitor():
|
|
611
|
+
while not stop_event.is_set():
|
|
612
|
+
# Memory usage of the current process
|
|
613
|
+
if callback:
|
|
614
|
+
callback(current_memory_usage())
|
|
615
|
+
time.sleep(interval_seconds)
|
|
616
|
+
|
|
617
|
+
stop_event = threading.Event()
|
|
618
|
+
monitor_thread = threading.Thread(target=monitor)
|
|
619
|
+
monitor_thread.start()
|
|
620
|
+
|
|
621
|
+
return stop_event, monitor_thread
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def thread_target(monitor, loop):
|
|
625
|
+
"""
|
|
626
|
+
This function is intended to be run in a separate thread.
|
|
627
|
+
It sets up an event loop and runs an asynchronous function within that loop.
|
|
628
|
+
"""
|
|
629
|
+
# Set the event loop for the current thread
|
|
630
|
+
asyncio.set_event_loop(loop)
|
|
631
|
+
loop.run_until_complete(monitor())
|
|
632
|
+
loop.close()
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
async def monitor_memory_usage_async(
|
|
636
|
+
callback: Optional[Callable[[float], Any]],
|
|
637
|
+
interval_seconds: float = 1.0,
|
|
638
|
+
):
|
|
639
|
+
"""
|
|
640
|
+
Monitor and logs memory usage periodically to the same log file.
|
|
641
|
+
"""
|
|
642
|
+
new_loop = asyncio.new_event_loop()
|
|
643
|
+
|
|
644
|
+
async def monitor():
|
|
645
|
+
while not stop_event.is_set():
|
|
646
|
+
# Memory usage of the current process
|
|
647
|
+
if callback:
|
|
648
|
+
memory = current_memory_usage()
|
|
649
|
+
await callback(memory)
|
|
650
|
+
await asyncio.sleep(interval_seconds)
|
|
651
|
+
|
|
652
|
+
stop_event = threading.Event()
|
|
653
|
+
monitor_thread = threading.Thread(target=thread_target, args=(monitor, new_loop))
|
|
654
|
+
monitor_thread.start()
|
|
655
|
+
|
|
656
|
+
return stop_event, monitor_thread
|