mage-ai 0.9.75__py3-none-any.whl → 0.9.77__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mage-ai might be problematic. Click here for more details.
- mage_ai/api/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 +11 -3
- 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 +6 -1
- mage_ai/data_integrations/destinations/constants.py +2 -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/models/block/__init__.py +29 -23
- 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 +1 -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 +3 -0
- mage_ai/data_preparation/models/pipeline.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_loaders/airtable.py +28 -0
- mage_ai/data_preparation/templates/repo/io_config.yaml +2 -0
- mage_ai/io/airtable.py +104 -0
- mage_ai/io/base.py +1 -0
- 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/postgres.py +3 -0
- mage_ai/io/redshift.py +13 -0
- mage_ai/io/sql.py +1 -0
- mage_ai/orchestration/db/__init__.py +20 -0
- 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 +107 -5
- 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 +2 -0
- mage_ai/orchestration/utils/distributed_lock.py +8 -1
- 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 +2 -2
- mage_ai/server/frontend_dist/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-782dd4a6b13e1c42.js +2 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
- 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-d25d07db166cbb04.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/{webpack-0bc44da590c7cf85.js → webpack-b9a067f3bd0a3a05.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/{38-PtskJFUTYUpRhT1qF_ → qR0jauUABqPaFMjUsYeoG}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/compute.html +2 -2
- mage_ai/server/frontend_dist/files.html +2 -2
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-data-products.html +2 -2
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/files.html +2 -2
- mage_ai/server/frontend_dist/manage/overview.html +2 -2
- mage_ai/server/frontend_dist/manage/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +2 -2
- mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist/manage/users.html +2 -2
- mage_ai/server/frontend_dist/manage.html +2 -2
- mage_ai/server/frontend_dist/oauth.html +3 -3
- mage_ai/server/frontend_dist/overview.html +2 -2
- mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +5 -5
- mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist/templates.html +2 -2
- mage_ai/server/frontend_dist/terminal.html +2 -2
- mage_ai/server/frontend_dist/test.html +2 -2
- mage_ai/server/frontend_dist/triggers.html +2 -2
- mage_ai/server/frontend_dist/v2/canvas.html +2 -2
- mage_ai/server/frontend_dist/v2.html +2 -2
- mage_ai/server/frontend_dist/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-ee5e328aaf51c698.js +2 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
- 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/pipelines/[pipeline]/settings-03d9bca3bc5e6088.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/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
- 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/_next/static/{dxnSzgIvSG4Ke5LM-tPQX → iCySon3_GCldnbC5U7C-s}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
- mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/v2/canvas.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/v2.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
- mage_ai/server/scheduler_manager.py +2 -0
- mage_ai/server/terminal_server.py +3 -0
- mage_ai/settings/server.py +4 -0
- mage_ai/streaming/sources/kafka.py +2 -1
- mage_ai/tests/data_preparation/executors/test_block_executor.py +3 -3
- mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +1 -3
- mage_ai/tests/data_preparation/models/test_variable.py +2 -0
- mage_ai/tests/io/create_table/test_postgresql.py +3 -2
- mage_ai/tests/orchestration/notification/test_sender.py +5 -1
- mage_ai/tests/streaming/sources/test_kafka.py +2 -2
- mage_ai/usage_statistics/logger.py +99 -15
- mage_ai-0.9.77.dist-info/METADATA +356 -0
- {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/RECORD +211 -208
- {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/WHEEL +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/449-f689774546860ca4.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-13bf3b7dcef50c29.js +0 -2
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-b99379d0aa6a8c25.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-e51cd04bd4d1fffe.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-0abf8a1b7243f93b.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-38187954b6ec4b40.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-3ee783f5139c76a1.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/449-f689774546860ca4.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-0392ef723ea2c6f8.js +0 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-b99379d0aa6a8c25.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-e51cd04bd4d1fffe.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-0abf8a1b7243f93b.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-38187954b6ec4b40.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-3ee783f5139c76a1.js +0 -1
- mage_ai-0.9.75.dist-info/METADATA +0 -377
- /mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-13bf3b7dcef50c29.js.LICENSE.txt → _app-782dd4a6b13e1c42.js.LICENSE.txt} +0 -0
- /mage_ai/server/frontend_dist/_next/static/{38-PtskJFUTYUpRhT1qF_ → qR0jauUABqPaFMjUsYeoG}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-0392ef723ea2c6f8.js.LICENSE.txt → _app-ee5e328aaf51c698.js.LICENSE.txt} +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{dxnSzgIvSG4Ke5LM-tPQX → iCySon3_GCldnbC5U7C-s}/_ssgManifest.js +0 -0
- {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info/licenses}/LICENSE +0 -0
- {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/top_level.txt +0 -0
|
@@ -100,6 +100,7 @@ PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes +
|
|
|
100
100
|
PipelineSchedulePolicy.allow_read(PipelineSchedulePresenter.default_attributes + [
|
|
101
101
|
'event_matchers',
|
|
102
102
|
'next_pipeline_run_date',
|
|
103
|
+
'rotate_token',
|
|
103
104
|
'tags',
|
|
104
105
|
], scopes=[
|
|
105
106
|
OauthScope.CLIENT_PRIVATE,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from mage_ai.api.operations import constants
|
|
2
2
|
from mage_ai.api.presenters.BasePresenter import BasePresenter
|
|
3
|
+
from mage_ai.settings.server import HIDE_API_TRIGGER_TOKEN
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class PipelineSchedulePresenter(BasePresenter):
|
|
@@ -32,8 +33,6 @@ class PipelineSchedulePresenter(BasePresenter):
|
|
|
32
33
|
])
|
|
33
34
|
data['tags'] = sorted([tag.name for tag in self.get_tag_associations])
|
|
34
35
|
data['next_pipeline_run_date'] = self.model.next_execution_date()
|
|
35
|
-
|
|
36
|
-
return data
|
|
37
36
|
elif 'with_runtime_average' == display_format:
|
|
38
37
|
data = self.model.to_dict()
|
|
39
38
|
data['runtime_average'] = self.model.runtime_average()
|
|
@@ -47,6 +46,16 @@ class PipelineSchedulePresenter(BasePresenter):
|
|
|
47
46
|
else:
|
|
48
47
|
data = self.model.to_dict()
|
|
49
48
|
|
|
49
|
+
if display_format == constants.UPDATE:
|
|
50
|
+
rotate_token = kwargs.get(
|
|
51
|
+
'payload', dict(),
|
|
52
|
+
).get(
|
|
53
|
+
'pipeline_schedule', dict(),
|
|
54
|
+
).get('rotate_token')
|
|
55
|
+
else:
|
|
56
|
+
rotate_token = False
|
|
57
|
+
if HIDE_API_TRIGGER_TOKEN and not rotate_token:
|
|
58
|
+
data['token'] = '[API_TOKEN_PLACEHOLDER]'
|
|
50
59
|
return data
|
|
51
60
|
|
|
52
61
|
|
|
@@ -32,6 +32,14 @@ class GitFileResource(GenericResource):
|
|
|
32
32
|
pass
|
|
33
33
|
|
|
34
34
|
file_path_absolute = os.path.join(git_manager.repo_path, file_path)
|
|
35
|
+
|
|
36
|
+
# Prevent path traversal by resolving the absolute path location
|
|
37
|
+
# and checking if it's within the repo
|
|
38
|
+
if not os.path.abspath(file_path_absolute).startswith(
|
|
39
|
+
os.path.abspath(git_manager.repo_path)
|
|
40
|
+
):
|
|
41
|
+
raise Exception("Access denied: Attempted path traversal")
|
|
42
|
+
|
|
35
43
|
file = File.from_path(file_path_absolute)
|
|
36
44
|
if not file.exists():
|
|
37
45
|
file = File.from_path(file_path_absolute, '')
|
|
@@ -29,7 +29,8 @@ from mage_ai.orchestration.db.models.tags import (
|
|
|
29
29
|
)
|
|
30
30
|
from mage_ai.settings.platform import project_platform_activated
|
|
31
31
|
from mage_ai.settings.repo import get_repo_path
|
|
32
|
-
from mage_ai.
|
|
32
|
+
from mage_ai.settings.server import HIDE_API_TRIGGER_TOKEN
|
|
33
|
+
from mage_ai.shared.hash import ignore_keys, merge_dict
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
class PipelineScheduleResource(DatabaseResource):
|
|
@@ -282,6 +283,7 @@ class PipelineScheduleResource(DatabaseResource):
|
|
|
282
283
|
|
|
283
284
|
@safe_db_query
|
|
284
285
|
def update(self, payload, **kwargs):
|
|
286
|
+
# Update associated event matchers
|
|
285
287
|
arr = payload.pop('event_matchers', None)
|
|
286
288
|
event_matchers = []
|
|
287
289
|
if arr is not None:
|
|
@@ -320,6 +322,7 @@ class PipelineScheduleResource(DatabaseResource):
|
|
|
320
322
|
]
|
|
321
323
|
em.update(pipeline_schedules=ps)
|
|
322
324
|
|
|
325
|
+
# Update associated tags
|
|
323
326
|
tag_names = payload.pop('tags', None)
|
|
324
327
|
if tag_names is not None:
|
|
325
328
|
# 1. Fetch all tag associations
|
|
@@ -408,7 +411,11 @@ class PipelineScheduleResource(DatabaseResource):
|
|
|
408
411
|
|
|
409
412
|
old_name = self.model.name
|
|
410
413
|
|
|
411
|
-
|
|
414
|
+
# Rotate token
|
|
415
|
+
if payload.get('rotate_token'):
|
|
416
|
+
payload['token'] = uuid.uuid4().hex
|
|
417
|
+
|
|
418
|
+
resource = super().update(ignore_keys(payload, ['rotate_token']))
|
|
412
419
|
updated_model = resource.model
|
|
413
420
|
|
|
414
421
|
repo_path = get_repo_path(user=self.current_user)
|
|
@@ -424,9 +431,10 @@ class PipelineScheduleResource(DatabaseResource):
|
|
|
424
431
|
sla=updated_model.sla,
|
|
425
432
|
start_time=updated_model.start_time,
|
|
426
433
|
status=updated_model.status,
|
|
427
|
-
token=updated_model.token,
|
|
428
434
|
variables=updated_model.variables,
|
|
429
435
|
)
|
|
436
|
+
if not HIDE_API_TRIGGER_TOKEN:
|
|
437
|
+
trigger.token = updated_model.token
|
|
430
438
|
|
|
431
439
|
update_only_if_exists = (
|
|
432
440
|
not pipeline.should_save_trigger_in_code_automatically()
|
|
@@ -8,6 +8,7 @@ from mage_ai.data_preparation.models.triggers import (
|
|
|
8
8
|
from mage_ai.orchestration.db import safe_db_query
|
|
9
9
|
from mage_ai.orchestration.db.models.schedules import PipelineSchedule
|
|
10
10
|
from mage_ai.settings.repo import get_repo_path
|
|
11
|
+
from mage_ai.settings.server import HIDE_API_TRIGGER_TOKEN
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class PipelineTriggerResource(GenericResource):
|
|
@@ -50,9 +51,10 @@ class PipelineTriggerResource(GenericResource):
|
|
|
50
51
|
sla=pipeline_schedule.sla,
|
|
51
52
|
start_time=pipeline_schedule.start_time,
|
|
52
53
|
status=pipeline_schedule.status,
|
|
53
|
-
token=pipeline_schedule.token,
|
|
54
54
|
variables=pipeline_schedule.variables,
|
|
55
55
|
)
|
|
56
|
+
if not HIDE_API_TRIGGER_TOKEN:
|
|
57
|
+
trigger.token = pipeline_schedule.token
|
|
56
58
|
else:
|
|
57
59
|
trigger = Trigger(**payload)
|
|
58
60
|
|
|
@@ -6,7 +6,7 @@ from mage_ai.authentication.ldap import new_ldap_connection
|
|
|
6
6
|
from mage_ai.authentication.oauth2 import encode_token, generate_access_token
|
|
7
7
|
from mage_ai.authentication.passwords import verify_password
|
|
8
8
|
from mage_ai.authentication.providers.constants import NAME_TO_PROVIDER
|
|
9
|
-
from mage_ai.orchestration.db import safe_db_query
|
|
9
|
+
from mage_ai.orchestration.db import safe_db_query, safe_db_query_async
|
|
10
10
|
from mage_ai.orchestration.db.models.oauth import Role, User
|
|
11
11
|
from mage_ai.settings import (
|
|
12
12
|
AUTHENTICATION_MODE,
|
|
@@ -20,7 +20,7 @@ from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
|
20
20
|
|
|
21
21
|
class SessionResource(BaseResource):
|
|
22
22
|
@classmethod
|
|
23
|
-
@
|
|
23
|
+
@safe_db_query_async
|
|
24
24
|
async def create(self, payload, _, **kwargs):
|
|
25
25
|
email = payload.get('email')
|
|
26
26
|
password = payload.get('password')
|
|
@@ -163,7 +163,7 @@ class SyncResource(GenericResource):
|
|
|
163
163
|
access_token = user_payload.pop('access_token', None)
|
|
164
164
|
if access_token:
|
|
165
165
|
secret_name = get_access_token_secret_name(user=user)
|
|
166
|
-
secret = Secret.
|
|
166
|
+
secret = Secret.repo_query.filter(Secret.name == secret_name).one_or_none()
|
|
167
167
|
if secret:
|
|
168
168
|
secret.delete()
|
|
169
169
|
create_secret(secret_name, access_token, repo_name=repo_name)
|
mage_ai/cli/main.py
CHANGED
|
@@ -194,7 +194,11 @@ def run(
|
|
|
194
194
|
from mage_ai.orchestration.db.models.schedules import PipelineRun
|
|
195
195
|
from mage_ai.orchestration.utils.git import log_git_sync, run_git_sync
|
|
196
196
|
from mage_ai.server.logger import Logger
|
|
197
|
-
from mage_ai.settings import
|
|
197
|
+
from mage_ai.settings import (
|
|
198
|
+
SENTRY_DSN,
|
|
199
|
+
SENTRY_SERVER_NAME,
|
|
200
|
+
SENTRY_TRACES_SAMPLE_RATE,
|
|
201
|
+
)
|
|
198
202
|
from mage_ai.shared.hash import merge_dict
|
|
199
203
|
|
|
200
204
|
logger = Logger().new_server_logger(__name__)
|
|
@@ -204,6 +208,7 @@ def run(
|
|
|
204
208
|
sentry_sdk.init(
|
|
205
209
|
sentry_dsn,
|
|
206
210
|
traces_sample_rate=SENTRY_TRACES_SAMPLE_RATE,
|
|
211
|
+
server_name=SENTRY_SERVER_NAME,
|
|
207
212
|
)
|
|
208
213
|
(enable_new_relic, application) = initialize_new_relic()
|
|
209
214
|
|
|
@@ -5,6 +5,7 @@ DESTINATIONS = [
|
|
|
5
5
|
dict(name='Clickhouse'),
|
|
6
6
|
dict(name='Delta Lake Azure'),
|
|
7
7
|
dict(name='Delta Lake S3'),
|
|
8
|
+
dict(name='Doris'),
|
|
8
9
|
dict(name='Elasticsearch'),
|
|
9
10
|
dict(name='Google Cloud Storage'),
|
|
10
11
|
dict(name='Kafka'),
|
|
@@ -21,5 +22,6 @@ DESTINATIONS = [
|
|
|
21
22
|
dict(name='Redshift'),
|
|
22
23
|
dict(name='Salesforce'),
|
|
23
24
|
dict(name='Snowflake'),
|
|
25
|
+
dict(name='Teradata'),
|
|
24
26
|
dict(name='Trino'),
|
|
25
27
|
]
|
|
@@ -3,6 +3,7 @@ from mage_ai.shared.hash import index_by
|
|
|
3
3
|
|
|
4
4
|
SQL_SOURCES = [
|
|
5
5
|
dict(name='BigQuery'),
|
|
6
|
+
dict(name='Doris'),
|
|
6
7
|
dict(
|
|
7
8
|
name='Microsoft SQL Server',
|
|
8
9
|
uuid='mssql',
|
|
@@ -53,6 +54,7 @@ SOURCES = sorted([
|
|
|
53
54
|
dict(name='Sftp'),
|
|
54
55
|
dict(name='Stripe'),
|
|
55
56
|
dict(name='Tableau'),
|
|
57
|
+
dict(name='Teradata'),
|
|
56
58
|
dict(name='Twitter Ads'),
|
|
57
59
|
dict(name='Zendesk'),
|
|
58
60
|
] + SQL_SOURCES, key=lambda x: x['name'])
|
|
@@ -693,7 +693,7 @@ class BlockExecutor:
|
|
|
693
693
|
),
|
|
694
694
|
tags=tags,
|
|
695
695
|
)
|
|
696
|
-
self.
|
|
696
|
+
self.execute_callback(
|
|
697
697
|
'on_failure',
|
|
698
698
|
block_run_id=block_run_id,
|
|
699
699
|
callback_kwargs=dict(__error=error, retry=self.retry_metadata),
|
|
@@ -748,7 +748,7 @@ class BlockExecutor:
|
|
|
748
748
|
# success callback because this isn’t the last data integration block that needs
|
|
749
749
|
# to run.
|
|
750
750
|
if not data_integration_metadata or is_original_block:
|
|
751
|
-
self.
|
|
751
|
+
self.execute_callback(
|
|
752
752
|
'on_success',
|
|
753
753
|
block_run_id=block_run_id,
|
|
754
754
|
callback_kwargs=dict(retry=self.retry_metadata),
|
|
@@ -1253,7 +1253,7 @@ class BlockExecutor:
|
|
|
1253
1253
|
|
|
1254
1254
|
return result
|
|
1255
1255
|
|
|
1256
|
-
def
|
|
1256
|
+
def execute_callback(
|
|
1257
1257
|
self,
|
|
1258
1258
|
callback: str,
|
|
1259
1259
|
global_vars: Dict,
|
|
@@ -1275,6 +1275,11 @@ class BlockExecutor:
|
|
|
1275
1275
|
dynamic_block_index: Index of the dynamic block.
|
|
1276
1276
|
dynamic_upstream_block_uuids: List of UUIDs of the dynamic upstream blocks.
|
|
1277
1277
|
"""
|
|
1278
|
+
if logging_tags is None:
|
|
1279
|
+
logging_tags = self.build_tags(
|
|
1280
|
+
block_run_id=block_run_id,
|
|
1281
|
+
pipeline_run_id=pipeline_run.id if pipeline_run is not None else None,
|
|
1282
|
+
)
|
|
1278
1283
|
upstream_block_uuids_override = []
|
|
1279
1284
|
if is_dynamic_block_child(self.block):
|
|
1280
1285
|
if not self.block_run and block_run_id:
|
|
@@ -10,10 +10,13 @@ from mage_ai.data_preparation.logging.logger import DictLogger
|
|
|
10
10
|
from mage_ai.data_preparation.logging.logger_manager_factory import LoggerManagerFactory
|
|
11
11
|
from mage_ai.data_preparation.models.pipeline import Pipeline
|
|
12
12
|
from mage_ai.orchestration.db.models.schedules import BlockRun, PipelineRun
|
|
13
|
+
from mage_ai.server.logger import Logger
|
|
13
14
|
from mage_ai.shared.hash import merge_dict
|
|
14
15
|
from mage_ai.usage_statistics.constants import EventNameType, EventObjectType
|
|
15
16
|
from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
16
17
|
|
|
18
|
+
logger = Logger().new_server_logger(__name__)
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
class PipelineExecutor:
|
|
19
22
|
def __init__(self, pipeline: Pipeline, execution_partition: str = None):
|
|
@@ -53,25 +56,38 @@ class PipelineExecutor:
|
|
|
53
56
|
update_status (bool): Whether to update the execution status.
|
|
54
57
|
**kwargs: Additional keyword arguments.
|
|
55
58
|
"""
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
59
|
+
# Create the async task to execute
|
|
60
|
+
async def _execute_task():
|
|
61
|
+
if pipeline_run_id is None:
|
|
62
|
+
# Execute the pipeline without block runs
|
|
63
|
+
await self.pipeline.execute(
|
|
64
|
+
analyze_outputs=analyze_outputs,
|
|
65
|
+
global_vars=global_vars,
|
|
66
|
+
run_sensors=run_sensors,
|
|
67
|
+
run_tests=run_tests,
|
|
68
|
+
update_status=update_status,
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
# Supported pipeline types: Standard batch pipeline
|
|
72
|
+
pipeline_run = PipelineRun.query.get(pipeline_run_id)
|
|
73
|
+
if pipeline_run.status != PipelineRun.PipelineRunStatus.RUNNING:
|
|
74
|
+
return
|
|
75
|
+
await self.__run_blocks(
|
|
76
|
+
pipeline_run,
|
|
77
|
+
allow_blocks_to_fail=allow_blocks_to_fail,
|
|
78
|
+
global_vars=global_vars,
|
|
79
|
+
)
|
|
80
|
+
# Execute the task based on current context
|
|
81
|
+
try:
|
|
82
|
+
loop = asyncio.get_running_loop()
|
|
83
|
+
logger.info(f'[PipelineExecutor] Found running loop {loop}')
|
|
84
|
+
# We're in an async context, use create_task
|
|
85
|
+
task = asyncio.create_task(_execute_task())
|
|
86
|
+
loop.run_until_complete(task)
|
|
87
|
+
except RuntimeError:
|
|
88
|
+
# No running loop, safe to use asyncio.run
|
|
89
|
+
logger.info('[PipelineExecutor] No running loop, using asyncio.run')
|
|
90
|
+
asyncio.run(_execute_task())
|
|
75
91
|
|
|
76
92
|
self.logger_manager.output_logs_to_destination()
|
|
77
93
|
|
|
@@ -3941,7 +3941,6 @@ class Block(
|
|
|
3941
3941
|
for v in b.output_variables(execution_partition=execution_partition):
|
|
3942
3942
|
objs.append(
|
|
3943
3943
|
self.get_variable_object(
|
|
3944
|
-
self.pipeline_uuid,
|
|
3945
3944
|
b.uuid,
|
|
3946
3945
|
v,
|
|
3947
3946
|
partition=execution_partition,
|
|
@@ -4465,29 +4464,36 @@ class CallbackBlock(AddonBlock):
|
|
|
4465
4464
|
elif 'on_success' == callback:
|
|
4466
4465
|
callback_functions_legacy = success_functions
|
|
4467
4466
|
callback_status = CallbackStatus.SUCCESS
|
|
4467
|
+
elif 'on_cancelled' == callback:
|
|
4468
|
+
callback_functions_legacy = []
|
|
4469
|
+
callback_status = CallbackStatus.CANCELLED
|
|
4468
4470
|
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4471
|
+
if callback_status in [CallbackStatus.FAILURE, CallbackStatus.SUCCESS]:
|
|
4472
|
+
# Fetch input variables
|
|
4473
|
+
input_vars, kwargs_vars, upstream_block_uuids = self.fetch_input_variables(
|
|
4474
|
+
None,
|
|
4475
|
+
dynamic_block_index=dynamic_block_index,
|
|
4476
|
+
dynamic_block_indexes=dynamic_block_indexes,
|
|
4477
|
+
dynamic_upstream_block_uuids=dynamic_upstream_block_uuids,
|
|
4478
|
+
execution_partition=execution_partition,
|
|
4479
|
+
from_notebook=from_notebook,
|
|
4480
|
+
global_vars=global_vars,
|
|
4481
|
+
metadata=metadata,
|
|
4482
|
+
upstream_block_uuids=[parent_block.uuid] if parent_block else None,
|
|
4483
|
+
upstream_block_uuids_override=upstream_block_uuids_override,
|
|
4484
|
+
)
|
|
4485
|
+
# Copied logic from the method self.execute_block
|
|
4486
|
+
outputs_from_input_vars = {}
|
|
4487
|
+
upstream_block_uuids_length = len(upstream_block_uuids)
|
|
4488
|
+
for idx, input_var in enumerate(input_vars):
|
|
4489
|
+
if idx < upstream_block_uuids_length:
|
|
4490
|
+
upstream_block_uuid = upstream_block_uuids[idx]
|
|
4491
|
+
outputs_from_input_vars[upstream_block_uuid] = input_var
|
|
4492
|
+
outputs_from_input_vars[f'df_{idx + 1}'] = input_var
|
|
4493
|
+
else:
|
|
4494
|
+
input_vars = []
|
|
4495
|
+
kwargs_vars = []
|
|
4496
|
+
upstream_block_uuids = []
|
|
4491
4497
|
|
|
4492
4498
|
global_vars_copy = global_vars.copy()
|
|
4493
4499
|
for kwargs_var in kwargs_vars:
|
|
@@ -5,7 +5,9 @@ from typing import Any, Dict, Optional, Tuple, Union
|
|
|
5
5
|
|
|
6
6
|
import dbt.flags as flags
|
|
7
7
|
import pandas as pd
|
|
8
|
-
from dbt.adapters.base import BaseRelation
|
|
8
|
+
from dbt.adapters.base.relation import BaseRelation
|
|
9
|
+
from dbt.adapters.contracts.connection import AdapterResponse, Credentials
|
|
10
|
+
from dbt.adapters.contracts.relation import RelationType
|
|
9
11
|
from dbt.adapters.factory import (
|
|
10
12
|
Adapter,
|
|
11
13
|
cleanup_connections,
|
|
@@ -13,10 +15,10 @@ from dbt.adapters.factory import (
|
|
|
13
15
|
register_adapter,
|
|
14
16
|
reset_adapters,
|
|
15
17
|
)
|
|
16
|
-
from dbt.config.
|
|
18
|
+
from dbt.config.project import read_project_flags
|
|
17
19
|
from dbt.config.runtime import RuntimeConfig
|
|
18
|
-
from dbt.
|
|
19
|
-
from dbt.
|
|
20
|
+
from dbt.context.providers import generate_runtime_macro_context
|
|
21
|
+
from dbt.mp_context import get_mp_context
|
|
20
22
|
|
|
21
23
|
from mage_ai.data_preparation.models.block.dbt.profiles import Profiles
|
|
22
24
|
from mage_ai.shared.environments import is_debug
|
|
@@ -79,7 +81,11 @@ class DBTAdapter:
|
|
|
79
81
|
# remove interpolated profiles.yml
|
|
80
82
|
self.__profiles.clean()
|
|
81
83
|
|
|
82
|
-
def execute(
|
|
84
|
+
def execute(
|
|
85
|
+
self,
|
|
86
|
+
sql: str,
|
|
87
|
+
fetch: bool = False
|
|
88
|
+
) -> Tuple[AdapterResponse, pd.DataFrame]:
|
|
83
89
|
"""
|
|
84
90
|
Executes any sql statement using the dbt adapter.
|
|
85
91
|
|
|
@@ -135,6 +141,8 @@ class DBTAdapter:
|
|
|
135
141
|
package
|
|
136
142
|
)
|
|
137
143
|
|
|
144
|
+
self.__adapter.set_macro_resolver(manifest)
|
|
145
|
+
|
|
138
146
|
# create a context for the macro (e.g. downstream macros)
|
|
139
147
|
from dbt.context.providers import generate_runtime_macro_context
|
|
140
148
|
macro_context = generate_runtime_macro_context(
|
|
@@ -203,7 +211,7 @@ class DBTAdapter:
|
|
|
203
211
|
# set dbt flags
|
|
204
212
|
# Need to add profiles.yml file
|
|
205
213
|
try:
|
|
206
|
-
user_config =
|
|
214
|
+
user_config = read_project_flags(self.project_path, profiles_path)
|
|
207
215
|
except Exception as err:
|
|
208
216
|
print(f'[ERROR] DBTAdapter.open: {err}.')
|
|
209
217
|
|
|
@@ -211,7 +219,10 @@ class DBTAdapter:
|
|
|
211
219
|
not profiles_path.endswith('profiles.yml'):
|
|
212
220
|
|
|
213
221
|
try:
|
|
214
|
-
user_config =
|
|
222
|
+
user_config = read_project_flags(
|
|
223
|
+
self.project_path,
|
|
224
|
+
os.path.join(profiles_path, 'profiles.yml')
|
|
225
|
+
)
|
|
215
226
|
except Exception as err2:
|
|
216
227
|
print(f'[ERROR] DBTAdapter.open: {err2}.')
|
|
217
228
|
raise err
|
|
@@ -227,9 +238,10 @@ class DBTAdapter:
|
|
|
227
238
|
config = RuntimeConfig.from_args(adapter_config)
|
|
228
239
|
reset_adapters()
|
|
229
240
|
# register the correct adapter from config
|
|
230
|
-
register_adapter(config)
|
|
241
|
+
register_adapter(config, mp_context=get_mp_context())
|
|
231
242
|
# load the adapter
|
|
232
243
|
self.__adapter = get_adapter(config)
|
|
244
|
+
self.__adapter.set_macro_context_generator(generate_runtime_macro_context)
|
|
233
245
|
# connect
|
|
234
246
|
self.__adapter.acquire_connection('mage_dbt_adapter_' + uuid.uuid4().hex)
|
|
235
247
|
return self
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
CHILD_DATA_VARIABLE_UUID = 'output_0'
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
from typing import Any, Iterable, List, Optional, Sequence
|
|
2
2
|
|
|
3
3
|
from mage_ai.data.tabular.reader import read_metadata
|
|
4
|
-
from mage_ai.data_preparation.models.block.dynamic.constants import (
|
|
5
|
-
CHILD_DATA_VARIABLE_UUID,
|
|
6
|
-
)
|
|
7
4
|
from mage_ai.data_preparation.models.block.dynamic.utils import (
|
|
8
5
|
is_dynamic_block,
|
|
9
6
|
is_dynamic_block_child,
|
|
10
7
|
should_reduce_output,
|
|
11
8
|
)
|
|
9
|
+
from mage_ai.data_preparation.models.constants import CHILD_DATA_VARIABLE_UUID
|
|
12
10
|
from mage_ai.data_preparation.models.variables.cache import VariableAggregateCache
|
|
13
11
|
from mage_ai.data_preparation.models.variables.constants import (
|
|
14
12
|
VariableAggregateDataType,
|
|
@@ -343,7 +343,7 @@ def format_output_data(
|
|
|
343
343
|
columns=columns_to_display,
|
|
344
344
|
rows=[
|
|
345
345
|
list(row.values())
|
|
346
|
-
for row in json.loads(data[columns_to_display].
|
|
346
|
+
for row in json.loads(json.dumps(data[columns_to_display].to_dicts()))
|
|
347
347
|
],
|
|
348
348
|
),
|
|
349
349
|
resource_usage=resource_usage,
|
|
@@ -8,7 +8,10 @@ import pandas as pd
|
|
|
8
8
|
import simplejson
|
|
9
9
|
|
|
10
10
|
from mage_ai.data_preparation.models.block import Block
|
|
11
|
-
from mage_ai.data_preparation.models.constants import
|
|
11
|
+
from mage_ai.data_preparation.models.constants import (
|
|
12
|
+
CHILD_DATA_VARIABLE_UUID,
|
|
13
|
+
BlockType,
|
|
14
|
+
)
|
|
12
15
|
from mage_ai.data_preparation.models.variables.constants import (
|
|
13
16
|
DATAFRAME_CSV_FILE,
|
|
14
17
|
VariableType,
|
|
@@ -81,7 +84,10 @@ def execute_r_code(
|
|
|
81
84
|
|
|
82
85
|
if len(output_variable_objects) > 0:
|
|
83
86
|
df = pd.read_csv(
|
|
84
|
-
os.path.join(
|
|
87
|
+
os.path.join(
|
|
88
|
+
output_variable_objects[0].variable_path,
|
|
89
|
+
DATAFRAME_CSV_FILE
|
|
90
|
+
)
|
|
85
91
|
)
|
|
86
92
|
else:
|
|
87
93
|
df = None
|
|
@@ -129,14 +135,19 @@ def __render_r_script(
|
|
|
129
135
|
raise Exception(
|
|
130
136
|
f"Block execution for {block.type} with R language is not supported.",
|
|
131
137
|
)
|
|
132
|
-
template = template_env.get_template(
|
|
138
|
+
template = template_env.get_template(
|
|
139
|
+
BLOCK_TYPE_TO_EXECUTION_TEMPLATE[block.type]
|
|
140
|
+
)
|
|
133
141
|
|
|
134
142
|
output_variable_object = block.variable_object(
|
|
135
|
-
|
|
143
|
+
CHILD_DATA_VARIABLE_UUID,
|
|
136
144
|
execution_partition=execution_partition,
|
|
137
145
|
)
|
|
138
146
|
os.makedirs(output_variable_object.variable_path, exist_ok=True)
|
|
139
|
-
output_path = os.path.join(
|
|
147
|
+
output_path = os.path.join(
|
|
148
|
+
output_variable_object.variable_path,
|
|
149
|
+
DATAFRAME_CSV_FILE
|
|
150
|
+
)
|
|
140
151
|
|
|
141
152
|
global_vars_str = __render_global_vars(global_vars=global_vars)
|
|
142
153
|
|
|
@@ -150,6 +150,7 @@ def execute_sql_code(
|
|
|
150
150
|
interpolate_vars_options = dict(
|
|
151
151
|
block=block,
|
|
152
152
|
dynamic_block_index=dynamic_block_index,
|
|
153
|
+
execution_partition=execution_partition,
|
|
153
154
|
global_vars=global_vars,
|
|
154
155
|
)
|
|
155
156
|
|
|
@@ -368,6 +369,7 @@ def execute_sql_code(
|
|
|
368
369
|
loader,
|
|
369
370
|
block,
|
|
370
371
|
query_string,
|
|
372
|
+
disable_query_preprocessing=disable_query_preprocessing,
|
|
371
373
|
configuration=configuration,
|
|
372
374
|
should_query=should_query,
|
|
373
375
|
)
|
|
@@ -67,9 +67,17 @@ def execute_raw_sql(
|
|
|
67
67
|
query_string: str,
|
|
68
68
|
configuration: Dict = None,
|
|
69
69
|
should_query: bool = False,
|
|
70
|
+
disable_query_preprocessing: bool = False,
|
|
70
71
|
) -> List[Any]:
|
|
71
72
|
if configuration is None:
|
|
72
73
|
configuration = {}
|
|
74
|
+
|
|
75
|
+
if disable_query_preprocessing:
|
|
76
|
+
return loader.execute_query_raw(
|
|
77
|
+
query_string,
|
|
78
|
+
configuration=configuration,
|
|
79
|
+
)
|
|
80
|
+
|
|
73
81
|
queries = []
|
|
74
82
|
fetch_query_at_indexes = []
|
|
75
83
|
|
|
@@ -232,7 +232,8 @@ def interpolate_vars(
|
|
|
232
232
|
content: str,
|
|
233
233
|
global_vars: Dict = None,
|
|
234
234
|
block=None,
|
|
235
|
-
dynamic_block_index: int = None
|
|
235
|
+
dynamic_block_index: int = None,
|
|
236
|
+
execution_partition: str = None,
|
|
236
237
|
) -> str :
|
|
237
238
|
if not content:
|
|
238
239
|
return content
|
|
@@ -241,7 +242,10 @@ def interpolate_vars(
|
|
|
241
242
|
|
|
242
243
|
if block:
|
|
243
244
|
content = block.interpolate_content(
|
|
244
|
-
content,
|
|
245
|
+
content,
|
|
246
|
+
variables=global_vars,
|
|
247
|
+
dynamic_block_index=dynamic_block_index,
|
|
248
|
+
execution_partition=execution_partition,
|
|
245
249
|
)
|
|
246
250
|
|
|
247
251
|
return Template(
|
|
@@ -27,6 +27,7 @@ PIPELINES_FOLDER = 'pipelines'
|
|
|
27
27
|
PREFERENCES_FILE = '.preferences.yaml'
|
|
28
28
|
REPO_CONFIG_FILE = 'metadata.yaml'
|
|
29
29
|
VARIABLE_DIR = '.variables'
|
|
30
|
+
CHILD_DATA_VARIABLE_UUID = 'output_0'
|
|
30
31
|
|
|
31
32
|
PIPELINE_RUN_STATUS_LAST_RUN_FAILED = 'last_run_failed'
|
|
32
33
|
|
|
@@ -81,6 +82,7 @@ class BlockColor(StrEnum):
|
|
|
81
82
|
|
|
82
83
|
|
|
83
84
|
class CallbackStatus(StrEnum):
|
|
85
|
+
CANCELLED = 'cancelled'
|
|
84
86
|
FAILURE = 'failure'
|
|
85
87
|
SUCCESS = 'success'
|
|
86
88
|
|
|
@@ -125,6 +127,7 @@ BLOCK_LANGUAGE_TO_FILE_EXTENSION = {
|
|
|
125
127
|
|
|
126
128
|
|
|
127
129
|
CALLBACK_STATUSES = [
|
|
130
|
+
CallbackStatus.CANCELLED,
|
|
128
131
|
CallbackStatus.FAILURE,
|
|
129
132
|
CallbackStatus.SUCCESS,
|
|
130
133
|
]
|
|
@@ -2331,7 +2331,7 @@ class Pipeline:
|
|
|
2331
2331
|
):
|
|
2332
2332
|
# Introduce a small delay to prevent multiple changes from generating
|
|
2333
2333
|
# identical timestamps for the pipeline YAML file
|
|
2334
|
-
time.sleep(0.
|
|
2334
|
+
time.sleep(0.0005)
|
|
2335
2335
|
|
|
2336
2336
|
blocks_current = sorted([b.uuid for b in self.blocks_by_uuid.values()])
|
|
2337
2337
|
|
|
@@ -121,7 +121,10 @@ class LocalStorage(BaseStorage):
|
|
|
121
121
|
return pd.read_parquet(file_path, engine='pyarrow')
|
|
122
122
|
|
|
123
123
|
def read_polars_parquet(self, file_path: str, **kwargs) -> pl.DataFrame:
|
|
124
|
-
|
|
124
|
+
try:
|
|
125
|
+
return pl.read_parquet(file_path, use_pyarrow=True)
|
|
126
|
+
except Exception:
|
|
127
|
+
return pl.read_parquet(file_path)
|
|
125
128
|
|
|
126
129
|
def write_csv(self, df: pd.DataFrame, file_path: str) -> None:
|
|
127
130
|
File.create_parent_directories(file_path)
|