gooddata-pipelines 1.65.1.dev1__tar.gz → 1.65.1.dev3__tar.gz
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.
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/PKG-INFO +2 -2
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/pyproject.toml +2 -2
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/__init__.py +2 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/input_processor.py +76 -25
- gooddata_pipelines-1.65.1.dev3/src/gooddata_pipelines/ldm_extension/models/custom_data_object.py +184 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_filters.py +1 -2
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/test_input_processor.py +49 -0
- gooddata_pipelines-1.65.1.dev3/tests/test_ldm_extension/test_models/test_custom_data_object.py +208 -0
- gooddata_pipelines-1.65.1.dev1/src/gooddata_pipelines/ldm_extension/models/custom_data_object.py +0 -106
- gooddata_pipelines-1.65.1.dev1/tests/test_ldm_extension/test_models/test_custom_data_object.py +0 -102
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/.gitignore +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/LICENSE.txt +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/Makefile +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/README.md +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/_version.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/api/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/api/gooddata_api.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/api/gooddata_api_wrapper.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/backup_input_processor.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/backup_manager.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/base_manager.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/constants.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/csv_reader.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/models/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/models/input_type.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/models/storage.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/models/workspace_response.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/restore_manager.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/storage/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/storage/azure_storage.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/storage/base_storage.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/storage/local_storage.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/backup_and_restore/storage/s3_storage.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/input_validator.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/ldm_extension_manager.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/models/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/models/aliases.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/ldm_extension/models/analytical_object.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/logger/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/logger/logger.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/assets/wdf_setting.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/user_data_filters/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/user_data_filters/models/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/user_data_filters/models/udf_models.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/user_data_filters/user_data_filters.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/models/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/models/permissions.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/models/user_groups.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/models/users.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/permissions.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/user_groups.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/users/users.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/workspaces/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/workspaces/models.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_parser.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_validator.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/generic/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/generic/config.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/generic/provision.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/provisioning.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/utils/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/utils/context_objects.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/utils/exceptions.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/provisioning/utils/utils.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/py.typed +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/utils/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/utils/decorators.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/utils/file_utils.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/utils/rate_limiter.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/backup_and_restore/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/backup_and_restore/test_backup.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/backup_and_restore/test_backup_input_processor.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/backup_and_restore/test_restore.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/conftest.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_conf.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/analytical_dashboard_extensions/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/analytical_dashboards/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/dashboard_plugins/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/filter_contexts/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/metrics/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/visualization_objects/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/ldm/datasets/test.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/ldm/date_instances/testinstance.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/analytical_dashboard_extensions/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/analytical_dashboards/id.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/dashboard_plugins/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/filter_contexts/id.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/metrics/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/visualization_objects/test.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/ldm/datasets/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/ldm/date_instances/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/analytical_dashboard_extensions/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/analytical_dashboards/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/dashboard_plugins/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/filter_contexts/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/metrics/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/visualization_objects/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/ldm/datasets/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/ldm/date_instances/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/user_data_filters/.gitkeep +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/backup/test_local_conf.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/custom_fields/response_get_all_dashboards.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/custom_fields/response_get_all_metrics.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/custom_fields/response_get_all_visualizations.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/mock_responses.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/profiles.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/permissions/existing_upstream_permissions.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/permissions/permissions_expected_full_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/permissions/permissions_expected_incremental_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/permissions/permissions_input_full_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/permissions/permissions_input_incremental_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/existing_upstream_users.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/profile_response_content.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_expected_full_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_expected_incremental_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_input_full_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_input_full_load_modifies_protected_user.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_input_incremental_load.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_input_incremental_load_deletes_protected_user.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/provisioning/entities/users/users_input_incremental_load_modifies_protected_user.json +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/restore/test_conf.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/restore/test_udf_root/filter1.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/restore/test_udf_root/filter2.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/restore/test_udf_root/user_data_filters/filter1.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/data/restore/test_udf_root/user_data_filters/filter2.yaml +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/panther/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/panther/test_api_wrapper.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/panther/test_sdk_wrapper.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/users/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/users/test_permissions.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/users/test_user_groups.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/users/test_users.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/workspaces/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/workspaces/test_provisioning.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/workspaces/test_workspace.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/workspaces/test_workspace_data_filters.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/workspaces/test_workspace_data_parser.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/entities/workspaces/test_workspace_data_validator.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/provisioning/test_provisioning.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/conftest.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/test_input_validator.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/test_ldm_extension_manager.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/test_merge_ldm.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/test_models/__init__.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/test_ldm_extension/test_models/test_analytical_object.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/utils/test_decorators.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tests/utils/test_rate_limiter.py +0 -0
- {gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gooddata-pipelines
|
|
3
|
-
Version: 1.65.1.
|
|
3
|
+
Version: 1.65.1.dev3
|
|
4
4
|
Summary: GoodData Cloud lifecycle automation pipelines
|
|
5
5
|
Author-email: GoodData <support@gooddata.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -10,7 +10,7 @@ Requires-Dist: azure-identity<2.0.0,>=1.15.0
|
|
|
10
10
|
Requires-Dist: azure-storage-blob<13.0.0,>=12.19.0
|
|
11
11
|
Requires-Dist: boto3-stubs<2.0.0,>=1.39.3
|
|
12
12
|
Requires-Dist: boto3<2.0.0,>=1.39.3
|
|
13
|
-
Requires-Dist: gooddata-sdk~=1.65.1.
|
|
13
|
+
Requires-Dist: gooddata-sdk~=1.65.1.dev3
|
|
14
14
|
Requires-Dist: pydantic<3.0.0,>=2.9.2
|
|
15
15
|
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
16
16
|
Requires-Dist: types-pyyaml<7.0.0,>=6.0.12.20250326
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# (C) 2025 GoodData Corporation
|
|
2
2
|
[project]
|
|
3
3
|
name = "gooddata-pipelines"
|
|
4
|
-
version = "1.65.1.
|
|
4
|
+
version = "1.65.1.dev3"
|
|
5
5
|
description = "GoodData Cloud lifecycle automation pipelines"
|
|
6
6
|
authors = [{ name = "GoodData", email = "support@gooddata.com" }]
|
|
7
7
|
license = "MIT"
|
|
@@ -11,7 +11,7 @@ dependencies = [
|
|
|
11
11
|
"pydantic (>=2.9.2,<3.0.0)",
|
|
12
12
|
"requests (>=2.32.3,<3.0.0)",
|
|
13
13
|
"types-requests (>1.0.0,<3.0.0)",
|
|
14
|
-
"gooddata-sdk~=1.65.1.
|
|
14
|
+
"gooddata-sdk~=1.65.1.dev3",
|
|
15
15
|
"boto3 (>=1.39.3,<2.0.0)",
|
|
16
16
|
"boto3-stubs (>=1.39.3,<2.0.0)",
|
|
17
17
|
"azure-storage-blob (>=12.19.0,<13.0.0)",
|
{gooddata_pipelines-1.65.1.dev1 → gooddata_pipelines-1.65.1.dev3}/src/gooddata_pipelines/__init__.py
RENAMED
|
@@ -26,6 +26,7 @@ from .ldm_extension.models.custom_data_object import (
|
|
|
26
26
|
CustomDatasetDefinition,
|
|
27
27
|
CustomFieldDefinition,
|
|
28
28
|
CustomFieldType,
|
|
29
|
+
ParentDatasetReference,
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
# -------- Provisioning --------
|
|
@@ -93,6 +94,7 @@ __all__ = [
|
|
|
93
94
|
"CustomFieldDefinition",
|
|
94
95
|
"ColumnDataType",
|
|
95
96
|
"CustomFieldType",
|
|
97
|
+
"ParentDatasetReference",
|
|
96
98
|
"provision",
|
|
97
99
|
"WorkflowType",
|
|
98
100
|
"__version__",
|
|
@@ -154,6 +154,46 @@ class LdmExtensionDataProcessor:
|
|
|
154
154
|
],
|
|
155
155
|
)
|
|
156
156
|
|
|
157
|
+
@staticmethod
|
|
158
|
+
def _build_parent_reference_sources(
|
|
159
|
+
definition: CustomDatasetDefinition,
|
|
160
|
+
) -> list[CatalogDeclarativeReferenceSource]:
|
|
161
|
+
"""Build the reference sources from either the new list or the legacy triple."""
|
|
162
|
+
if definition.parent_dataset_references:
|
|
163
|
+
return [
|
|
164
|
+
CatalogDeclarativeReferenceSource(
|
|
165
|
+
column=ref.source_column,
|
|
166
|
+
data_type=ref.data_type.value,
|
|
167
|
+
target=CatalogGrainIdentifier(
|
|
168
|
+
id=ref.attribute_id,
|
|
169
|
+
type=CustomFieldType.ATTRIBUTE.value,
|
|
170
|
+
),
|
|
171
|
+
)
|
|
172
|
+
for ref in definition.parent_dataset_references
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
# `check_reference_form` on the model guarantees all three legacy
|
|
176
|
+
# fields are set when `parent_dataset_references` is empty.
|
|
177
|
+
if (
|
|
178
|
+
definition.parent_dataset_reference_attribute_id is None
|
|
179
|
+
or definition.dataset_reference_source_column is None
|
|
180
|
+
or definition.dataset_reference_source_column_data_type is None
|
|
181
|
+
):
|
|
182
|
+
raise ValueError(
|
|
183
|
+
"Legacy reference fields must be set when "
|
|
184
|
+
"`parent_dataset_references` is not provided."
|
|
185
|
+
)
|
|
186
|
+
return [
|
|
187
|
+
CatalogDeclarativeReferenceSource(
|
|
188
|
+
column=definition.dataset_reference_source_column,
|
|
189
|
+
data_type=definition.dataset_reference_source_column_data_type.value,
|
|
190
|
+
target=CatalogGrainIdentifier(
|
|
191
|
+
id=definition.parent_dataset_reference_attribute_id,
|
|
192
|
+
type=CustomFieldType.ATTRIBUTE.value,
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
]
|
|
196
|
+
|
|
157
197
|
@staticmethod
|
|
158
198
|
def _get_sources(
|
|
159
199
|
dataset: CustomDataset,
|
|
@@ -253,6 +293,39 @@ class LdmExtensionDataProcessor:
|
|
|
253
293
|
# Get the data source info
|
|
254
294
|
dataset_source_table_id, dataset_sql = self._get_sources(dataset)
|
|
255
295
|
|
|
296
|
+
parent_reference_sources = self._build_parent_reference_sources(
|
|
297
|
+
dataset.definition
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
wdf_columns: (
|
|
301
|
+
list[CatalogDeclarativeWorkspaceDataFilterColumn] | None
|
|
302
|
+
) = None
|
|
303
|
+
wdf_references: (
|
|
304
|
+
list[CatalogDeclarativeWorkspaceDataFilterReferences] | None
|
|
305
|
+
) = None
|
|
306
|
+
wdf_id = dataset.definition.workspace_data_filter_id
|
|
307
|
+
wdf_column_name = (
|
|
308
|
+
dataset.definition.workspace_data_filter_column_name
|
|
309
|
+
)
|
|
310
|
+
# `check_wdf_pair` on the model guarantees both fields are set
|
|
311
|
+
# together or both omitted.
|
|
312
|
+
if wdf_id is not None and wdf_column_name is not None:
|
|
313
|
+
wdf_columns = [
|
|
314
|
+
CatalogDeclarativeWorkspaceDataFilterColumn(
|
|
315
|
+
name=wdf_column_name,
|
|
316
|
+
data_type=ColumnDataType.STRING.value,
|
|
317
|
+
)
|
|
318
|
+
]
|
|
319
|
+
wdf_references = [
|
|
320
|
+
CatalogDeclarativeWorkspaceDataFilterReferences(
|
|
321
|
+
filter_id=CatalogDatasetWorkspaceDataFilterIdentifier(
|
|
322
|
+
id=wdf_id
|
|
323
|
+
),
|
|
324
|
+
filter_column=wdf_column_name,
|
|
325
|
+
filter_column_data_type=ColumnDataType.STRING.value,
|
|
326
|
+
)
|
|
327
|
+
]
|
|
328
|
+
|
|
256
329
|
# Construct the declarative dataset object and append it to the list.
|
|
257
330
|
declarative_datasets.append(
|
|
258
331
|
CatalogDeclarativeDataset(
|
|
@@ -265,16 +338,7 @@ class LdmExtensionDataProcessor:
|
|
|
265
338
|
id=dataset.definition.parent_dataset_reference,
|
|
266
339
|
),
|
|
267
340
|
multivalue=True,
|
|
268
|
-
sources=
|
|
269
|
-
CatalogDeclarativeReferenceSource(
|
|
270
|
-
column=dataset.definition.dataset_reference_source_column,
|
|
271
|
-
data_type=dataset.definition.dataset_reference_source_column_data_type.value,
|
|
272
|
-
target=CatalogGrainIdentifier(
|
|
273
|
-
id=dataset.definition.parent_dataset_reference_attribute_id,
|
|
274
|
-
type=CustomFieldType.ATTRIBUTE.value,
|
|
275
|
-
),
|
|
276
|
-
)
|
|
277
|
-
],
|
|
341
|
+
sources=parent_reference_sources,
|
|
278
342
|
),
|
|
279
343
|
]
|
|
280
344
|
+ date_references,
|
|
@@ -283,21 +347,8 @@ class LdmExtensionDataProcessor:
|
|
|
283
347
|
facts=facts,
|
|
284
348
|
data_source_table_id=dataset_source_table_id,
|
|
285
349
|
sql=dataset_sql,
|
|
286
|
-
workspace_data_filter_columns=
|
|
287
|
-
|
|
288
|
-
name=dataset.definition.workspace_data_filter_column_name,
|
|
289
|
-
data_type=ColumnDataType.STRING.value,
|
|
290
|
-
)
|
|
291
|
-
],
|
|
292
|
-
workspace_data_filter_references=[
|
|
293
|
-
CatalogDeclarativeWorkspaceDataFilterReferences(
|
|
294
|
-
filter_id=CatalogDatasetWorkspaceDataFilterIdentifier(
|
|
295
|
-
id=dataset.definition.workspace_data_filter_id
|
|
296
|
-
),
|
|
297
|
-
filter_column=dataset.definition.workspace_data_filter_column_name,
|
|
298
|
-
filter_column_data_type=ColumnDataType.STRING.value,
|
|
299
|
-
)
|
|
300
|
-
],
|
|
350
|
+
workspace_data_filter_columns=wdf_columns,
|
|
351
|
+
workspace_data_filter_references=wdf_references,
|
|
301
352
|
tags=_effective_dataset_tags(dataset.definition),
|
|
302
353
|
)
|
|
303
354
|
)
|
gooddata_pipelines-1.65.1.dev3/src/gooddata_pipelines/ldm_extension/models/custom_data_object.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# (C) 2025 GoodData Corporation
|
|
2
|
+
"""This module defines enums and models used to represent the input data.
|
|
3
|
+
|
|
4
|
+
Models defined here are used to validate and structure the input data before
|
|
5
|
+
further processing.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field, model_validator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CustomFieldType(str, Enum):
|
|
14
|
+
"""GoodData field types."""
|
|
15
|
+
|
|
16
|
+
# NOTE: Start using StrEnum with Python 3.11
|
|
17
|
+
ATTRIBUTE = "attribute"
|
|
18
|
+
FACT = "fact"
|
|
19
|
+
DATE = "date"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ColumnDataType(str, Enum):
|
|
23
|
+
"""Supported data types"""
|
|
24
|
+
|
|
25
|
+
# NOTE: Start using StrEnum with Python 3.11
|
|
26
|
+
INT = "INT"
|
|
27
|
+
STRING = "STRING"
|
|
28
|
+
DATE = "DATE"
|
|
29
|
+
NUMERIC = "NUMERIC"
|
|
30
|
+
TIMESTAMP = "TIMESTAMP"
|
|
31
|
+
TIMESTAMP_TZ = "TIMESTAMP_TZ"
|
|
32
|
+
BOOLEAN = "BOOLEAN"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CustomFieldDefinition(BaseModel):
|
|
36
|
+
"""Input model for custom field definition."""
|
|
37
|
+
|
|
38
|
+
workspace_id: str
|
|
39
|
+
dataset_id: str
|
|
40
|
+
custom_field_id: str
|
|
41
|
+
custom_field_name: str
|
|
42
|
+
custom_field_type: CustomFieldType
|
|
43
|
+
custom_field_source_column: str
|
|
44
|
+
custom_field_source_column_data_type: ColumnDataType
|
|
45
|
+
description: str | None = Field(
|
|
46
|
+
default=None,
|
|
47
|
+
description="Declarative description on the attribute, fact, or date dataset.",
|
|
48
|
+
)
|
|
49
|
+
tags: list[str] | None = Field(
|
|
50
|
+
default=None,
|
|
51
|
+
description="If set, replaces the default tag list (dataset display name only).",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@model_validator(mode="after")
|
|
55
|
+
def check_ids_not_equal(self) -> "CustomFieldDefinition":
|
|
56
|
+
"""Check that custom field ID is not the same as dataset ID."""
|
|
57
|
+
if self.custom_field_id == self.dataset_id:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
f"Custom field ID {self.custom_field_id} cannot be the same as dataset ID {self.dataset_id}"
|
|
60
|
+
)
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ParentDatasetReference(BaseModel):
|
|
65
|
+
"""One column of a (possibly composite) join to the parent dataset.
|
|
66
|
+
|
|
67
|
+
A list of these on ``CustomDatasetDefinition.parent_dataset_references``
|
|
68
|
+
supports multi-column foreign keys. Each entry binds a source column on the
|
|
69
|
+
new dataset to a grain attribute on the parent.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
attribute_id: str = Field(
|
|
73
|
+
description="Attribute ID on the parent dataset that this column joins to.",
|
|
74
|
+
)
|
|
75
|
+
source_column: str = Field(
|
|
76
|
+
description="Column name on this dataset used to join to the parent.",
|
|
77
|
+
)
|
|
78
|
+
data_type: ColumnDataType = Field(
|
|
79
|
+
description="Data type of the source column.",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class CustomDatasetDefinition(BaseModel):
|
|
84
|
+
"""Input model for custom dataset definition."""
|
|
85
|
+
|
|
86
|
+
workspace_id: str
|
|
87
|
+
dataset_id: str
|
|
88
|
+
dataset_name: str
|
|
89
|
+
dataset_datasource_id: str
|
|
90
|
+
dataset_source_table: str | None
|
|
91
|
+
dataset_source_sql: str | None
|
|
92
|
+
parent_dataset_reference: str
|
|
93
|
+
parent_dataset_reference_attribute_id: str | None = Field(
|
|
94
|
+
default=None,
|
|
95
|
+
deprecated=(
|
|
96
|
+
"Use `parent_dataset_references` instead. "
|
|
97
|
+
"This field will be removed in a future release."
|
|
98
|
+
),
|
|
99
|
+
)
|
|
100
|
+
dataset_reference_source_column: str | None = Field(
|
|
101
|
+
default=None,
|
|
102
|
+
deprecated=(
|
|
103
|
+
"Use `parent_dataset_references` instead. "
|
|
104
|
+
"This field will be removed in a future release."
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
dataset_reference_source_column_data_type: ColumnDataType | None = Field(
|
|
108
|
+
default=None,
|
|
109
|
+
deprecated=(
|
|
110
|
+
"Use `parent_dataset_references` instead. "
|
|
111
|
+
"This field will be removed in a future release."
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
parent_dataset_references: list[ParentDatasetReference] | None = Field(
|
|
115
|
+
default=None,
|
|
116
|
+
description="List of references to the parent dataset.",
|
|
117
|
+
)
|
|
118
|
+
workspace_data_filter_id: str | None = None
|
|
119
|
+
workspace_data_filter_column_name: str | None = None
|
|
120
|
+
dataset_description: str | None = Field(
|
|
121
|
+
default=None,
|
|
122
|
+
description="Declarative description on the custom dataset.",
|
|
123
|
+
)
|
|
124
|
+
dataset_tags: list[str] | None = Field(
|
|
125
|
+
default=None,
|
|
126
|
+
description="If set, replaces the default tag list (dataset display name only).",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@model_validator(mode="after")
|
|
130
|
+
def check_source(self) -> "CustomDatasetDefinition":
|
|
131
|
+
"""At least one of dataset_source_table or dataset_source_sql is provided."""
|
|
132
|
+
if not (self.dataset_source_table or self.dataset_source_sql):
|
|
133
|
+
raise ValueError(
|
|
134
|
+
"One of dataset_source_table and dataset_source_sql must be provided"
|
|
135
|
+
)
|
|
136
|
+
if self.dataset_source_table and self.dataset_source_sql:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
"Only one of dataset_source_table and dataset_source_sql can be provided"
|
|
139
|
+
)
|
|
140
|
+
return self
|
|
141
|
+
|
|
142
|
+
@model_validator(mode="after")
|
|
143
|
+
def check_reference_form(self) -> "CustomDatasetDefinition":
|
|
144
|
+
"""Exactly one reference form must be set: either the new list or the legacy triple."""
|
|
145
|
+
has_new = bool(self.parent_dataset_references)
|
|
146
|
+
has_legacy = (
|
|
147
|
+
self.parent_dataset_reference_attribute_id is not None
|
|
148
|
+
or self.dataset_reference_source_column is not None
|
|
149
|
+
or self.dataset_reference_source_column_data_type is not None
|
|
150
|
+
)
|
|
151
|
+
if has_new and has_legacy:
|
|
152
|
+
raise ValueError(
|
|
153
|
+
"Set either `parent_dataset_references` or the legacy single-column "
|
|
154
|
+
"fields (`parent_dataset_reference_attribute_id`, "
|
|
155
|
+
"`dataset_reference_source_column`, "
|
|
156
|
+
"`dataset_reference_source_column_data_type`), not both."
|
|
157
|
+
)
|
|
158
|
+
if not has_new and not has_legacy:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
"Provide either `parent_dataset_references` or the legacy single-column "
|
|
161
|
+
"fields (`parent_dataset_reference_attribute_id`, "
|
|
162
|
+
"`dataset_reference_source_column`, "
|
|
163
|
+
"`dataset_reference_source_column_data_type`)."
|
|
164
|
+
)
|
|
165
|
+
return self
|
|
166
|
+
|
|
167
|
+
@model_validator(mode="after")
|
|
168
|
+
def check_wdf_pair(self) -> "CustomDatasetDefinition":
|
|
169
|
+
"""Workspace data filter id and column name must be provided together or both omitted."""
|
|
170
|
+
has_id = self.workspace_data_filter_id is not None
|
|
171
|
+
has_col = self.workspace_data_filter_column_name is not None
|
|
172
|
+
if has_id != has_col:
|
|
173
|
+
raise ValueError(
|
|
174
|
+
"workspace_data_filter_id and workspace_data_filter_column_name "
|
|
175
|
+
"must both be set or both be omitted"
|
|
176
|
+
)
|
|
177
|
+
return self
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class CustomDataset(BaseModel):
|
|
181
|
+
"""Custom dataset with its definition and custom fields."""
|
|
182
|
+
|
|
183
|
+
definition: CustomDatasetDefinition
|
|
184
|
+
custom_fields: list[CustomFieldDefinition]
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"""Module for managing workspace data filter settings in GoodData Cloud."""
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
6
7
|
from typing import Any
|
|
7
8
|
from uuid import uuid4
|
|
8
9
|
|
|
@@ -40,8 +41,6 @@ class WorkspaceDataFilterManager:
|
|
|
40
41
|
"""Loads a JSON template of a WDF setting and fills it with the given values."""
|
|
41
42
|
values = [str(value) for value in wdf_values]
|
|
42
43
|
|
|
43
|
-
import os
|
|
44
|
-
|
|
45
44
|
wdf_setting_path = os.path.join(
|
|
46
45
|
os.path.dirname(__file__), "../../assets/wdf_setting.json"
|
|
47
46
|
)
|
|
@@ -129,3 +129,52 @@ def test_datasets_to_ldm(mock_custom_dataset):
|
|
|
129
129
|
assert ds.workspace_data_filter_references[0].filter_id.id == "wdf1"
|
|
130
130
|
assert len(ldm.date_instances) == 1
|
|
131
131
|
assert ldm.date_instances[0].id == "date1"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_datasets_to_ldm_parent_dataset_references_composite():
|
|
135
|
+
"""Multi-column references via `parent_dataset_references` produce N sources."""
|
|
136
|
+
from gooddata_pipelines.ldm_extension.models.custom_data_object import (
|
|
137
|
+
CustomDatasetDefinition,
|
|
138
|
+
ParentDatasetReference,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
definition = CustomDatasetDefinition(
|
|
142
|
+
workspace_id="workspace1",
|
|
143
|
+
dataset_id="ds_composite",
|
|
144
|
+
dataset_name="Composite Dataset",
|
|
145
|
+
dataset_source_table="table1",
|
|
146
|
+
dataset_datasource_id="ds_source",
|
|
147
|
+
dataset_source_sql=None,
|
|
148
|
+
parent_dataset_reference="parent_ds",
|
|
149
|
+
parent_dataset_references=[
|
|
150
|
+
ParentDatasetReference(
|
|
151
|
+
attribute_id="parent_pk1",
|
|
152
|
+
source_column="src_col1",
|
|
153
|
+
data_type=ColumnDataType.STRING,
|
|
154
|
+
),
|
|
155
|
+
ParentDatasetReference(
|
|
156
|
+
attribute_id="parent_pk2",
|
|
157
|
+
source_column="src_col2",
|
|
158
|
+
data_type=ColumnDataType.INT,
|
|
159
|
+
),
|
|
160
|
+
],
|
|
161
|
+
workspace_data_filter_id="wdf1",
|
|
162
|
+
workspace_data_filter_column_name="col1",
|
|
163
|
+
)
|
|
164
|
+
ds = CustomDataset(definition=definition, custom_fields=[])
|
|
165
|
+
processor = LdmExtensionDataProcessor()
|
|
166
|
+
model = processor.datasets_to_ldm({"ds_composite": ds})
|
|
167
|
+
parent_ref = model.ldm.datasets[0].references[0]
|
|
168
|
+
assert len(parent_ref.sources) == 2
|
|
169
|
+
assert [s.column for s in parent_ref.sources] == ["src_col1", "src_col2"]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_datasets_to_ldm_legacy_reference_fallback(mock_dataset_definition):
|
|
173
|
+
"""When `parent_dataset_references` is not set, fall back to legacy fields."""
|
|
174
|
+
mock_dataset_definition.parent_dataset_references = None
|
|
175
|
+
ds = CustomDataset(definition=mock_dataset_definition, custom_fields=[])
|
|
176
|
+
processor = LdmExtensionDataProcessor()
|
|
177
|
+
model = processor.datasets_to_ldm({"ds1": ds})
|
|
178
|
+
parent_ref = model.ldm.datasets[0].references[0]
|
|
179
|
+
assert len(parent_ref.sources) == 1
|
|
180
|
+
assert parent_ref.sources[0].column == "ref_col"
|
gooddata_pipelines-1.65.1.dev3/tests/test_ldm_extension/test_models/test_custom_data_object.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# (C) 2025 GoodData Corporation
|
|
2
|
+
import pytest
|
|
3
|
+
from pydantic import ValidationError
|
|
4
|
+
|
|
5
|
+
from gooddata_pipelines.ldm_extension.models.custom_data_object import (
|
|
6
|
+
ColumnDataType,
|
|
7
|
+
CustomDataset,
|
|
8
|
+
CustomDatasetDefinition,
|
|
9
|
+
CustomFieldDefinition,
|
|
10
|
+
CustomFieldType,
|
|
11
|
+
ParentDatasetReference,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def make_valid_field_def(**kwargs):
|
|
16
|
+
data = {
|
|
17
|
+
"workspace_id": "ws1",
|
|
18
|
+
"dataset_id": "ds1",
|
|
19
|
+
"custom_field_id": "cf1",
|
|
20
|
+
"custom_field_name": "Custom Field",
|
|
21
|
+
"custom_field_type": CustomFieldType.ATTRIBUTE,
|
|
22
|
+
"custom_field_source_column": "col1",
|
|
23
|
+
"custom_field_source_column_data_type": ColumnDataType.STRING,
|
|
24
|
+
}
|
|
25
|
+
data.update(kwargs)
|
|
26
|
+
return data
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def make_valid_dataset_def(**kwargs):
|
|
30
|
+
data = {
|
|
31
|
+
"workspace_id": "ws1",
|
|
32
|
+
"dataset_id": "ds1",
|
|
33
|
+
"dataset_name": "Dataset",
|
|
34
|
+
"dataset_datasource_id": "dsrc1",
|
|
35
|
+
"dataset_source_table": "table1",
|
|
36
|
+
"dataset_source_sql": None,
|
|
37
|
+
"parent_dataset_reference": "parent_ds",
|
|
38
|
+
"parent_dataset_reference_attribute_id": "parent_attr",
|
|
39
|
+
"dataset_reference_source_column": "src_col",
|
|
40
|
+
"dataset_reference_source_column_data_type": ColumnDataType.STRING,
|
|
41
|
+
"workspace_data_filter_id": "wdf1",
|
|
42
|
+
"workspace_data_filter_column_name": "col1",
|
|
43
|
+
}
|
|
44
|
+
data.update(kwargs)
|
|
45
|
+
return data
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_custom_field_definition_valid():
|
|
49
|
+
field = CustomFieldDefinition(**make_valid_field_def())
|
|
50
|
+
assert field.custom_field_id == "cf1"
|
|
51
|
+
assert field.custom_field_type == CustomFieldType.ATTRIBUTE
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_custom_field_definition_cf_id_equals_dataset_id_raises():
|
|
55
|
+
data = make_valid_field_def(custom_field_id="ds1")
|
|
56
|
+
with pytest.raises(ValidationError) as exc:
|
|
57
|
+
CustomFieldDefinition(**data)
|
|
58
|
+
assert "cannot be the same as dataset ID" in str(exc.value)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_custom_dataset_definition_valid_table():
|
|
62
|
+
ds = CustomDatasetDefinition(**make_valid_dataset_def())
|
|
63
|
+
assert ds.dataset_source_table == "table1"
|
|
64
|
+
assert ds.dataset_source_sql is None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_custom_dataset_definition_valid_sql():
|
|
68
|
+
data = make_valid_dataset_def(
|
|
69
|
+
dataset_source_table=None, dataset_source_sql="SELECT 1"
|
|
70
|
+
)
|
|
71
|
+
ds = CustomDatasetDefinition(**data)
|
|
72
|
+
assert ds.dataset_source_sql == "SELECT 1"
|
|
73
|
+
assert ds.dataset_source_table is None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_custom_dataset_definition_both_none_raises():
|
|
77
|
+
data = make_valid_dataset_def(
|
|
78
|
+
dataset_source_table=None, dataset_source_sql=None
|
|
79
|
+
)
|
|
80
|
+
with pytest.raises(ValidationError) as exc:
|
|
81
|
+
CustomDatasetDefinition(**data)
|
|
82
|
+
assert "must be provided" in str(exc.value)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_custom_dataset_definition_both_provided_raises():
|
|
86
|
+
data = make_valid_dataset_def(
|
|
87
|
+
dataset_source_table="table1", dataset_source_sql="SELECT 1"
|
|
88
|
+
)
|
|
89
|
+
with pytest.raises(ValidationError) as exc:
|
|
90
|
+
CustomDatasetDefinition(**data)
|
|
91
|
+
assert (
|
|
92
|
+
"Only one of dataset_source_table and dataset_source_sql can be provided"
|
|
93
|
+
in str(exc.value)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_custom_dataset_model():
|
|
98
|
+
ds_def = CustomDatasetDefinition(**make_valid_dataset_def())
|
|
99
|
+
field_def = CustomFieldDefinition(**make_valid_field_def())
|
|
100
|
+
dataset = CustomDataset(definition=ds_def, custom_fields=[field_def])
|
|
101
|
+
assert dataset.definition.dataset_id == "ds1"
|
|
102
|
+
assert len(dataset.custom_fields) == 1
|
|
103
|
+
assert dataset.custom_fields[0].custom_field_id == "cf1"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_custom_dataset_definition_parent_dataset_references_optional():
|
|
107
|
+
"""The new composite-reference field is optional and defaults to None."""
|
|
108
|
+
ds = CustomDatasetDefinition(**make_valid_dataset_def())
|
|
109
|
+
assert ds.parent_dataset_references is None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_custom_dataset_definition_parent_dataset_references_accepted():
|
|
113
|
+
"""Composite references can be provided via the new list field."""
|
|
114
|
+
refs = [
|
|
115
|
+
ParentDatasetReference(
|
|
116
|
+
attribute_id="parent_pk1",
|
|
117
|
+
source_column="src_col1",
|
|
118
|
+
data_type=ColumnDataType.STRING,
|
|
119
|
+
),
|
|
120
|
+
ParentDatasetReference(
|
|
121
|
+
attribute_id="parent_pk2",
|
|
122
|
+
source_column="src_col2",
|
|
123
|
+
data_type=ColumnDataType.INT,
|
|
124
|
+
),
|
|
125
|
+
]
|
|
126
|
+
data = make_valid_dataset_def(
|
|
127
|
+
parent_dataset_reference_attribute_id=None,
|
|
128
|
+
dataset_reference_source_column=None,
|
|
129
|
+
dataset_reference_source_column_data_type=None,
|
|
130
|
+
parent_dataset_references=refs,
|
|
131
|
+
)
|
|
132
|
+
ds = CustomDatasetDefinition(**data)
|
|
133
|
+
assert ds.parent_dataset_references is not None
|
|
134
|
+
assert len(ds.parent_dataset_references) == 2
|
|
135
|
+
assert ds.parent_dataset_references[1].data_type == ColumnDataType.INT
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_custom_dataset_definition_no_reference_form_raises():
|
|
139
|
+
"""Providing neither the legacy fields nor `parent_dataset_references` is rejected."""
|
|
140
|
+
data = make_valid_dataset_def(
|
|
141
|
+
parent_dataset_reference_attribute_id=None,
|
|
142
|
+
dataset_reference_source_column=None,
|
|
143
|
+
dataset_reference_source_column_data_type=None,
|
|
144
|
+
)
|
|
145
|
+
with pytest.raises(ValidationError) as exc:
|
|
146
|
+
CustomDatasetDefinition(**data)
|
|
147
|
+
assert "Provide either" in str(exc.value)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_custom_dataset_definition_mixed_reference_forms_raises():
|
|
151
|
+
"""Setting both legacy fields and `parent_dataset_references` is rejected."""
|
|
152
|
+
data = make_valid_dataset_def(
|
|
153
|
+
parent_dataset_references=[
|
|
154
|
+
ParentDatasetReference(
|
|
155
|
+
attribute_id="parent_pk",
|
|
156
|
+
source_column="src_col",
|
|
157
|
+
data_type=ColumnDataType.STRING,
|
|
158
|
+
)
|
|
159
|
+
],
|
|
160
|
+
)
|
|
161
|
+
with pytest.raises(ValidationError) as exc:
|
|
162
|
+
CustomDatasetDefinition(**data)
|
|
163
|
+
assert "not both" in str(exc.value)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_custom_dataset_definition_legacy_reference_fields_optional():
|
|
167
|
+
data = make_valid_dataset_def(
|
|
168
|
+
parent_dataset_reference_attribute_id=None,
|
|
169
|
+
dataset_reference_source_column=None,
|
|
170
|
+
dataset_reference_source_column_data_type=None,
|
|
171
|
+
parent_dataset_references=[
|
|
172
|
+
ParentDatasetReference(
|
|
173
|
+
attribute_id="parent_pk",
|
|
174
|
+
source_column="src_col",
|
|
175
|
+
data_type=ColumnDataType.STRING,
|
|
176
|
+
)
|
|
177
|
+
],
|
|
178
|
+
)
|
|
179
|
+
ds = CustomDatasetDefinition(**data)
|
|
180
|
+
assert ds.dataset_reference_source_column is None
|
|
181
|
+
assert ds.parent_dataset_references is not None
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_custom_dataset_definition_wdf_optional_both_none():
|
|
185
|
+
data = make_valid_dataset_def(
|
|
186
|
+
workspace_data_filter_id=None, workspace_data_filter_column_name=None
|
|
187
|
+
)
|
|
188
|
+
ds = CustomDatasetDefinition(**data)
|
|
189
|
+
assert ds.workspace_data_filter_id is None
|
|
190
|
+
assert ds.workspace_data_filter_column_name is None
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_custom_dataset_definition_wdf_only_id_raises():
|
|
194
|
+
data = make_valid_dataset_def(
|
|
195
|
+
workspace_data_filter_id="wdf1", workspace_data_filter_column_name=None
|
|
196
|
+
)
|
|
197
|
+
with pytest.raises(ValidationError) as exc:
|
|
198
|
+
CustomDatasetDefinition(**data)
|
|
199
|
+
assert "both be set or both be omitted" in str(exc.value)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_custom_dataset_definition_wdf_only_column_raises():
|
|
203
|
+
data = make_valid_dataset_def(
|
|
204
|
+
workspace_data_filter_id=None, workspace_data_filter_column_name="col1"
|
|
205
|
+
)
|
|
206
|
+
with pytest.raises(ValidationError) as exc:
|
|
207
|
+
CustomDatasetDefinition(**data)
|
|
208
|
+
assert "both be set or both be omitted" in str(exc.value)
|