gooddata-pipelines 1.64.1.dev1__tar.gz → 1.64.1.dev2__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.
Files changed (159) hide show
  1. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/PKG-INFO +2 -2
  2. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/pyproject.toml +2 -2
  3. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/input_processor.py +82 -5
  4. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/ldm_extension_manager.py +70 -4
  5. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/models/custom_data_object.py +17 -1
  6. gooddata_pipelines-1.64.1.dev2/tests/test_ldm_extension/conftest.py +84 -0
  7. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/test_ldm_extension/test_input_processor.py +33 -76
  8. gooddata_pipelines-1.64.1.dev2/tests/test_ldm_extension/test_ldm_extension_manager.py +395 -0
  9. gooddata_pipelines-1.64.1.dev2/tests/test_ldm_extension/test_merge_ldm.py +84 -0
  10. gooddata_pipelines-1.64.1.dev1/tests/test_ldm_extension/test_ldm_extension_manager.py +0 -194
  11. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/.gitignore +0 -0
  12. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/LICENSE.txt +0 -0
  13. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/Makefile +0 -0
  14. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/README.md +0 -0
  15. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/__init__.py +0 -0
  16. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/_version.py +0 -0
  17. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/api/__init__.py +0 -0
  18. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/api/gooddata_api.py +0 -0
  19. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/api/gooddata_api_wrapper.py +0 -0
  20. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/__init__.py +0 -0
  21. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/backup_input_processor.py +0 -0
  22. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/backup_manager.py +0 -0
  23. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/base_manager.py +0 -0
  24. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/constants.py +0 -0
  25. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/csv_reader.py +0 -0
  26. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/models/__init__.py +0 -0
  27. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/models/input_type.py +0 -0
  28. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/models/storage.py +0 -0
  29. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/models/workspace_response.py +0 -0
  30. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/restore_manager.py +0 -0
  31. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/storage/__init__.py +0 -0
  32. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/storage/azure_storage.py +0 -0
  33. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/storage/base_storage.py +0 -0
  34. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/storage/local_storage.py +0 -0
  35. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/backup_and_restore/storage/s3_storage.py +0 -0
  36. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/__init__.py +0 -0
  37. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/input_validator.py +0 -0
  38. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/models/__init__.py +0 -0
  39. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/models/aliases.py +0 -0
  40. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/ldm_extension/models/analytical_object.py +0 -0
  41. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/logger/__init__.py +0 -0
  42. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/logger/logger.py +0 -0
  43. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/__init__.py +0 -0
  44. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/assets/wdf_setting.json +0 -0
  45. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/__init__.py +0 -0
  46. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/user_data_filters/__init__.py +0 -0
  47. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/user_data_filters/models/__init__.py +0 -0
  48. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/user_data_filters/models/udf_models.py +0 -0
  49. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/user_data_filters/user_data_filters.py +0 -0
  50. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/__init__.py +0 -0
  51. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/models/__init__.py +0 -0
  52. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/models/permissions.py +0 -0
  53. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/models/user_groups.py +0 -0
  54. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/models/users.py +0 -0
  55. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/permissions.py +0 -0
  56. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/user_groups.py +0 -0
  57. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/users/users.py +0 -0
  58. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/workspaces/__init__.py +0 -0
  59. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/workspaces/models.py +0 -0
  60. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace.py +0 -0
  61. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_filters.py +0 -0
  62. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_parser.py +0 -0
  63. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_validator.py +0 -0
  64. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/generic/__init__.py +0 -0
  65. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/generic/config.py +0 -0
  66. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/generic/provision.py +0 -0
  67. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/provisioning.py +0 -0
  68. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/utils/__init__.py +0 -0
  69. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/utils/context_objects.py +0 -0
  70. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/utils/exceptions.py +0 -0
  71. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/provisioning/utils/utils.py +0 -0
  72. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/py.typed +0 -0
  73. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/utils/__init__.py +0 -0
  74. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/utils/decorators.py +0 -0
  75. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/utils/file_utils.py +0 -0
  76. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/src/gooddata_pipelines/utils/rate_limiter.py +0 -0
  77. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/__init__.py +0 -0
  78. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/backup_and_restore/__init__.py +0 -0
  79. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/backup_and_restore/test_backup.py +0 -0
  80. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/backup_and_restore/test_backup_input_processor.py +0 -0
  81. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/backup_and_restore/test_restore.py +0 -0
  82. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/conftest.py +0 -0
  83. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/__init__.py +0 -0
  84. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/__init__.py +0 -0
  85. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_conf.yaml +0 -0
  86. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  87. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  88. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  89. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  90. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/metrics/.gitkeep +0 -0
  91. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  92. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/ldm/datasets/test.yaml +0 -0
  93. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  94. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  95. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  96. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  97. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  98. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/metrics/.gitkeep +0 -0
  99. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  100. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/ldm/datasets/.gitkeep +0 -0
  101. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/ldm/date_instances/.gitkeep +0 -0
  102. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  103. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  104. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  105. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  106. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/metrics/.gitkeep +0 -0
  107. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/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
  108. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/ldm/datasets/.gitkeep +0 -0
  109. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/ldm/date_instances/.gitkeep +0 -0
  110. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/user_data_filters/.gitkeep +0 -0
  111. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/backup/test_local_conf.yaml +0 -0
  112. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/custom_fields/response_get_all_dashboards.json +0 -0
  113. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/custom_fields/response_get_all_metrics.json +0 -0
  114. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/custom_fields/response_get_all_visualizations.json +0 -0
  115. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/mock_responses.py +0 -0
  116. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/profiles.yaml +0 -0
  117. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/permissions/existing_upstream_permissions.json +0 -0
  118. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/permissions/permissions_expected_full_load.json +0 -0
  119. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/permissions/permissions_expected_incremental_load.json +0 -0
  120. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/permissions/permissions_input_full_load.json +0 -0
  121. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/permissions/permissions_input_incremental_load.json +0 -0
  122. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/existing_upstream_users.json +0 -0
  123. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/profile_response_content.json +0 -0
  124. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_expected_full_load.json +0 -0
  125. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_expected_incremental_load.json +0 -0
  126. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_input_full_load.json +0 -0
  127. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_input_full_load_modifies_protected_user.json +0 -0
  128. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_input_incremental_load.json +0 -0
  129. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_input_incremental_load_deletes_protected_user.json +0 -0
  130. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/provisioning/entities/users/users_input_incremental_load_modifies_protected_user.json +0 -0
  131. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/restore/test_conf.yaml +0 -0
  132. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/restore/test_udf_root/filter1.yaml +0 -0
  133. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/restore/test_udf_root/filter2.yaml +0 -0
  134. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/restore/test_udf_root/user_data_filters/filter1.yaml +0 -0
  135. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/data/restore/test_udf_root/user_data_filters/filter2.yaml +0 -0
  136. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/panther/__init__.py +0 -0
  137. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/panther/test_api_wrapper.py +0 -0
  138. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/panther/test_sdk_wrapper.py +0 -0
  139. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/__init__.py +0 -0
  140. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/__init__.py +0 -0
  141. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/users/__init__.py +0 -0
  142. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/users/test_permissions.py +0 -0
  143. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/users/test_user_groups.py +0 -0
  144. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/users/test_users.py +0 -0
  145. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/workspaces/__init__.py +0 -0
  146. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/workspaces/test_provisioning.py +0 -0
  147. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/workspaces/test_workspace.py +0 -0
  148. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/workspaces/test_workspace_data_filters.py +0 -0
  149. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/workspaces/test_workspace_data_parser.py +0 -0
  150. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/entities/workspaces/test_workspace_data_validator.py +0 -0
  151. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/provisioning/test_provisioning.py +0 -0
  152. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/test_ldm_extension/__init__.py +0 -0
  153. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/test_ldm_extension/test_input_validator.py +0 -0
  154. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/test_ldm_extension/test_models/__init__.py +0 -0
  155. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/test_ldm_extension/test_models/test_analytical_object.py +0 -0
  156. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/test_ldm_extension/test_models/test_custom_data_object.py +0 -0
  157. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/utils/test_decorators.py +0 -0
  158. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tests/utils/test_rate_limiter.py +0 -0
  159. {gooddata_pipelines-1.64.1.dev1 → gooddata_pipelines-1.64.1.dev2}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gooddata-pipelines
3
- Version: 1.64.1.dev1
3
+ Version: 1.64.1.dev2
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.64.1.dev1
13
+ Requires-Dist: gooddata-sdk~=1.64.1.dev2
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.64.1.dev1"
4
+ version = "1.64.1.dev2"
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.64.1.dev1",
14
+ "gooddata-sdk~=1.64.1.dev2",
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)",
@@ -5,6 +5,8 @@ This module is responsible for converting validated custom datasets and fields
5
5
  into objects defined in the GoodData Python SDK.
6
6
  """
7
7
 
8
+ import copy
9
+
8
10
  from gooddata_sdk.catalog.identifier import (
9
11
  CatalogDatasetWorkspaceDataFilterIdentifier,
10
12
  CatalogGrainIdentifier,
@@ -36,11 +38,26 @@ from gooddata_pipelines.ldm_extension.models.aliases import DatasetId
36
38
  from gooddata_pipelines.ldm_extension.models.custom_data_object import (
37
39
  ColumnDataType,
38
40
  CustomDataset,
41
+ CustomDatasetDefinition,
39
42
  CustomFieldDefinition,
40
43
  CustomFieldType,
41
44
  )
42
45
 
43
46
 
47
+ def _effective_field_tags(
48
+ dataset_name: str, custom_field: CustomFieldDefinition
49
+ ) -> list[str]:
50
+ if custom_field.tags is not None:
51
+ return list(custom_field.tags)
52
+ return [dataset_name]
53
+
54
+
55
+ def _effective_dataset_tags(definition: CustomDatasetDefinition) -> list[str]:
56
+ if definition.dataset_tags is not None:
57
+ return list(definition.dataset_tags)
58
+ return [definition.dataset_name]
59
+
60
+
44
61
  class LdmExtensionDataProcessor:
45
62
  """Create GoodData LDM from validated custom datasets and fields."""
46
63
 
@@ -77,7 +94,8 @@ class LdmExtensionDataProcessor:
77
94
  source_column=custom_field.custom_field_source_column,
78
95
  labels=[],
79
96
  source_column_data_type=custom_field.custom_field_source_column_data_type.value,
80
- tags=[dataset_name],
97
+ description=custom_field.description,
98
+ tags=_effective_field_tags(dataset_name, custom_field),
81
99
  )
82
100
 
83
101
  @staticmethod
@@ -91,7 +109,8 @@ class LdmExtensionDataProcessor:
91
109
  title=custom_field.custom_field_name,
92
110
  source_column=custom_field.custom_field_source_column,
93
111
  source_column_data_type=custom_field.custom_field_source_column_data_type.value,
94
- tags=[dataset_name],
112
+ description=custom_field.description,
113
+ tags=_effective_field_tags(dataset_name, custom_field),
95
114
  )
96
115
 
97
116
  def _date_from_field(
@@ -109,7 +128,8 @@ class LdmExtensionDataProcessor:
109
128
  title_pattern="%titleBase - %granularityTitle",
110
129
  ),
111
130
  granularities=self.DATE_GRANULARITIES,
112
- tags=[dataset_name],
131
+ description=custom_field.description,
132
+ tags=_effective_field_tags(dataset_name, custom_field),
113
133
  )
114
134
 
115
135
  @staticmethod
@@ -258,7 +278,7 @@ class LdmExtensionDataProcessor:
258
278
  ),
259
279
  ]
260
280
  + date_references,
261
- description=None,
281
+ description=dataset.definition.dataset_description,
262
282
  attributes=attributes,
263
283
  facts=facts,
264
284
  data_source_table_id=dataset_source_table_id,
@@ -278,7 +298,7 @@ class LdmExtensionDataProcessor:
278
298
  filter_column_data_type=ColumnDataType.STRING.value,
279
299
  )
280
300
  ],
281
- tags=[dataset.definition.dataset_name],
301
+ tags=_effective_dataset_tags(dataset.definition),
282
302
  )
283
303
  )
284
304
 
@@ -287,3 +307,60 @@ class LdmExtensionDataProcessor:
287
307
  datasets=declarative_datasets, date_instances=date_instances
288
308
  )
289
309
  return CatalogDeclarativeModel(ldm=ldm)
310
+
311
+ def merge_custom_ldm_into_existing(
312
+ self,
313
+ existing: CatalogDeclarativeModel,
314
+ custom_datasets: dict[DatasetId, CustomDataset],
315
+ *,
316
+ remove_managed_datasets_missing_from_input: bool = False,
317
+ management_tag: str | None = None,
318
+ ) -> CatalogDeclarativeModel:
319
+ """Merge datasets produced from ``custom_datasets`` into an existing declarative LDM.
320
+
321
+ Custom datasets and date instances that share an ``id`` with the fragment replace
322
+ their previous definitions. When ``remove_managed_datasets_missing_from_input`` is
323
+ set, datasets that carry ``management_tag`` but are absent from the incoming
324
+ fragment are removed first (typical for tooling-owned extension datasets).
325
+
326
+ Any other pre-existing LDM objects (previously uploaded extensions whose ids
327
+ are not in the incoming fragment) are preserved unchanged.
328
+ """
329
+ fragment = self.datasets_to_ldm(custom_datasets)
330
+ fragment_ldm = fragment.ldm or CatalogDeclarativeLdm(
331
+ datasets=[], date_instances=[]
332
+ )
333
+
334
+ result = copy.deepcopy(existing)
335
+ result_ldm = result.ldm or CatalogDeclarativeLdm(
336
+ datasets=[], date_instances=[]
337
+ )
338
+ result.ldm = result_ldm
339
+
340
+ incoming_dataset_ids = {d.id for d in fragment_ldm.datasets}
341
+ incoming_date_ids = {d.id for d in fragment_ldm.date_instances}
342
+
343
+ datasets = list(result_ldm.datasets)
344
+ if remove_managed_datasets_missing_from_input and management_tag:
345
+ datasets = [
346
+ d
347
+ for d in datasets
348
+ if not (
349
+ d.tags
350
+ and management_tag in d.tags
351
+ and d.id not in incoming_dataset_ids
352
+ )
353
+ ]
354
+ datasets = [d for d in datasets if d.id not in incoming_dataset_ids]
355
+ datasets.extend(fragment_ldm.datasets)
356
+ result_ldm.datasets = datasets
357
+
358
+ date_instances = [
359
+ d
360
+ for d in result_ldm.date_instances
361
+ if d.id not in incoming_date_ids
362
+ ]
363
+ date_instances.extend(fragment_ldm.date_instances)
364
+ result_ldm.date_instances = date_instances
365
+
366
+ return result
@@ -3,6 +3,9 @@
3
3
 
4
4
  from pathlib import Path
5
5
 
6
+ from gooddata_sdk.catalog.workspace.declarative_model.workspace.logical_model.ldm import (
7
+ CatalogDeclarativeModel,
8
+ )
6
9
  from gooddata_sdk.sdk import GoodDataSdk
7
10
  from gooddata_sdk.utils import PROFILES_FILE_PATH, profile_content
8
11
 
@@ -147,9 +150,35 @@ class LdmExtensionManager:
147
150
  # If the set of new invalid relations is a subset of the current one,
148
151
  return set_new_invalid_relations.issubset(set_current_invalid_relations)
149
152
 
153
+ def _ldm_payload_for_workspace(
154
+ self,
155
+ workspace_id: str,
156
+ datasets: dict[DatasetId, CustomDataset],
157
+ *,
158
+ merge_into_existing_ldm: bool,
159
+ remove_managed_datasets_missing_from_input: bool,
160
+ management_tag: str | None,
161
+ ) -> CatalogDeclarativeModel:
162
+ """Build the declarative LDM payload to upload for one workspace."""
163
+ if not merge_into_existing_ldm:
164
+ return self._processor.datasets_to_ldm(datasets)
165
+ current = self._sdk.catalog_workspace_content.get_declarative_ldm(
166
+ workspace_id
167
+ )
168
+ return self._processor.merge_custom_ldm_into_existing(
169
+ current,
170
+ datasets,
171
+ remove_managed_datasets_missing_from_input=remove_managed_datasets_missing_from_input,
172
+ management_tag=management_tag,
173
+ )
174
+
150
175
  def _process_with_relations_check(
151
176
  self,
152
177
  validated_data: dict[WorkspaceId, dict[DatasetId, CustomDataset]],
178
+ *,
179
+ merge_into_existing_ldm: bool = False,
180
+ remove_managed_datasets_missing_from_input: bool = False,
181
+ management_tag: str | None = None,
153
182
  ) -> None:
154
183
  """Check whether relations of analytical objects are valid before and after
155
184
  updating the LDM in the GoodData workspace.
@@ -173,7 +202,13 @@ class LdmExtensionManager:
173
202
  # Put the LDM with custom datasets into the GoodData workspace.
174
203
  self._sdk.catalog_workspace_content.put_declarative_ldm(
175
204
  workspace_id=workspace_id,
176
- ldm=self._processor.datasets_to_ldm(datasets),
205
+ ldm=self._ldm_payload_for_workspace(
206
+ workspace_id,
207
+ datasets,
208
+ merge_into_existing_ldm=merge_into_existing_ldm,
209
+ remove_managed_datasets_missing_from_input=remove_managed_datasets_missing_from_input,
210
+ management_tag=management_tag,
211
+ ),
177
212
  )
178
213
 
179
214
  # Get a set of objects with invalid relations from the new workspace state
@@ -232,13 +267,23 @@ class LdmExtensionManager:
232
267
  def _process_without_relations_check(
233
268
  self,
234
269
  validated_data: dict[WorkspaceId, dict[DatasetId, CustomDataset]],
270
+ *,
271
+ merge_into_existing_ldm: bool = False,
272
+ remove_managed_datasets_missing_from_input: bool = False,
273
+ management_tag: str | None = None,
235
274
  ) -> None:
236
275
  """Update the LDM in the GoodData workspace without checking relations."""
237
276
  for workspace_id, datasets in validated_data.items():
238
277
  # Put the LDM with custom datasets into the GoodData workspace.
239
278
  self._sdk.catalog_workspace_content.put_declarative_ldm(
240
279
  workspace_id=workspace_id,
241
- ldm=self._processor.datasets_to_ldm(datasets),
280
+ ldm=self._ldm_payload_for_workspace(
281
+ workspace_id,
282
+ datasets,
283
+ merge_into_existing_ldm=merge_into_existing_ldm,
284
+ remove_managed_datasets_missing_from_input=remove_managed_datasets_missing_from_input,
285
+ management_tag=management_tag,
286
+ ),
242
287
  )
243
288
  self._log_success_message(workspace_id)
244
289
 
@@ -251,6 +296,9 @@ class LdmExtensionManager:
251
296
  custom_datasets: list[CustomDatasetDefinition],
252
297
  custom_fields: list[CustomFieldDefinition],
253
298
  check_relations: bool = True,
299
+ merge_into_existing_ldm: bool = False,
300
+ remove_managed_datasets_missing_from_input: bool = False,
301
+ management_tag: str | None = None,
254
302
  ) -> None:
255
303
  """Create custom datasets and fields in GoodData workspaces.
256
304
 
@@ -266,6 +314,14 @@ class LdmExtensionManager:
266
314
  after updating the LDM. If the number of invalid relations increases,
267
315
  the LDM will be reverted to its previous state. If False, the check
268
316
  is skiped and the LDM is updated directly. Defaults to True.
317
+ merge_into_existing_ldm (bool): When True, load the workspace LDM first and merge
318
+ the generated custom datasets and date instances into it instead of uploading
319
+ only the extension fragment. Defaults to False for backward compatibility.
320
+ remove_managed_datasets_missing_from_input (bool): When ``merge_into_existing_ldm``
321
+ is True, remove existing datasets that contain ``management_tag`` but whose
322
+ dataset id is not present in this ``process`` call (tooling cleanup).
323
+ management_tag (str | None): Tag value used with
324
+ ``remove_managed_datasets_missing_from_input``.
269
325
 
270
326
  Raises:
271
327
  ValueError: If there are validation errors in the dataset or field definitions.
@@ -278,6 +334,16 @@ class LdmExtensionManager:
278
334
 
279
335
  if check_relations:
280
336
  # Process the validated data with relations check.
281
- self._process_with_relations_check(validated_data)
337
+ self._process_with_relations_check(
338
+ validated_data,
339
+ merge_into_existing_ldm=merge_into_existing_ldm,
340
+ remove_managed_datasets_missing_from_input=remove_managed_datasets_missing_from_input,
341
+ management_tag=management_tag,
342
+ )
282
343
  else:
283
- self._process_without_relations_check(validated_data)
344
+ self._process_without_relations_check(
345
+ validated_data,
346
+ merge_into_existing_ldm=merge_into_existing_ldm,
347
+ remove_managed_datasets_missing_from_input=remove_managed_datasets_missing_from_input,
348
+ management_tag=management_tag,
349
+ )
@@ -7,7 +7,7 @@ further processing.
7
7
 
8
8
  from enum import Enum
9
9
 
10
- from pydantic import BaseModel, model_validator
10
+ from pydantic import BaseModel, Field, model_validator
11
11
 
12
12
 
13
13
  class CustomFieldType(str, Enum):
@@ -42,6 +42,14 @@ class CustomFieldDefinition(BaseModel):
42
42
  custom_field_type: CustomFieldType
43
43
  custom_field_source_column: str
44
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
+ )
45
53
 
46
54
  @model_validator(mode="after")
47
55
  def check_ids_not_equal(self) -> "CustomFieldDefinition":
@@ -68,6 +76,14 @@ class CustomDatasetDefinition(BaseModel):
68
76
  dataset_reference_source_column_data_type: ColumnDataType
69
77
  workspace_data_filter_id: str
70
78
  workspace_data_filter_column_name: str
79
+ dataset_description: str | None = Field(
80
+ default=None,
81
+ description="Declarative description on the custom dataset.",
82
+ )
83
+ dataset_tags: list[str] | None = Field(
84
+ default=None,
85
+ description="If set, replaces the default tag list (dataset display name only).",
86
+ )
71
87
 
72
88
  @model_validator(mode="after")
73
89
  def check_source(self) -> "CustomDatasetDefinition":
@@ -0,0 +1,84 @@
1
+ # (C) 2025 GoodData Corporation
2
+ import pytest
3
+
4
+ from gooddata_pipelines.ldm_extension.models.custom_data_object import (
5
+ ColumnDataType,
6
+ CustomDataset,
7
+ CustomDatasetDefinition,
8
+ CustomFieldDefinition,
9
+ CustomFieldType,
10
+ )
11
+
12
+
13
+ @pytest.fixture
14
+ def mock_custom_field_attribute():
15
+ return CustomFieldDefinition(
16
+ workspace_id="workspace1",
17
+ dataset_id="ds1",
18
+ custom_field_id="attr1",
19
+ custom_field_name="Attribute 1",
20
+ custom_field_type=CustomFieldType.ATTRIBUTE,
21
+ custom_field_source_column="col_attr1",
22
+ custom_field_source_column_data_type=ColumnDataType.STRING,
23
+ )
24
+
25
+
26
+ @pytest.fixture
27
+ def mock_custom_field_fact():
28
+ return CustomFieldDefinition(
29
+ workspace_id="workspace1",
30
+ dataset_id="ds1",
31
+ custom_field_id="fact1",
32
+ custom_field_name="Fact 1",
33
+ custom_field_type=CustomFieldType.FACT,
34
+ custom_field_source_column="col_fact1",
35
+ custom_field_source_column_data_type=ColumnDataType.INT,
36
+ )
37
+
38
+
39
+ @pytest.fixture
40
+ def mock_custom_field_date():
41
+ return CustomFieldDefinition(
42
+ workspace_id="workspace1",
43
+ dataset_id="ds1",
44
+ custom_field_id="date1",
45
+ custom_field_name="Date 1",
46
+ custom_field_type=CustomFieldType.DATE,
47
+ custom_field_source_column="col_date1",
48
+ custom_field_source_column_data_type=ColumnDataType.DATE,
49
+ )
50
+
51
+
52
+ @pytest.fixture
53
+ def mock_dataset_definition():
54
+ return CustomDatasetDefinition(
55
+ workspace_id="workspace1",
56
+ dataset_id="ds1",
57
+ dataset_name="Dataset 1",
58
+ dataset_source_table="table1",
59
+ dataset_datasource_id="ds_source",
60
+ dataset_source_sql=None,
61
+ parent_dataset_reference="parent_ds",
62
+ parent_dataset_reference_attribute_id="parent_attr",
63
+ dataset_reference_source_column="ref_col",
64
+ dataset_reference_source_column_data_type=ColumnDataType.STRING,
65
+ workspace_data_filter_id="wdf1",
66
+ workspace_data_filter_column_name="col1",
67
+ )
68
+
69
+
70
+ @pytest.fixture
71
+ def mock_custom_dataset(
72
+ mock_dataset_definition,
73
+ mock_custom_field_attribute,
74
+ mock_custom_field_fact,
75
+ mock_custom_field_date,
76
+ ):
77
+ return CustomDataset(
78
+ definition=mock_dataset_definition,
79
+ custom_fields=[
80
+ mock_custom_field_attribute,
81
+ mock_custom_field_fact,
82
+ mock_custom_field_date,
83
+ ],
84
+ )
@@ -1,21 +1,29 @@
1
1
  # (C) 2025 GoodData Corporation
2
- import pytest
3
-
4
2
  from gooddata_pipelines.ldm_extension.input_processor import (
5
3
  LdmExtensionDataProcessor,
6
4
  )
7
5
  from gooddata_pipelines.ldm_extension.models.custom_data_object import (
8
6
  ColumnDataType,
9
7
  CustomDataset,
10
- CustomDatasetDefinition,
11
8
  CustomFieldDefinition,
12
9
  CustomFieldType,
13
10
  )
14
11
 
15
12
 
16
- @pytest.fixture
17
- def mock_custom_field_attribute():
18
- return CustomFieldDefinition(
13
+ def test_attribute_from_field(mock_custom_field_attribute):
14
+ attr = LdmExtensionDataProcessor._attribute_from_field(
15
+ "dataset_name", mock_custom_field_attribute
16
+ )
17
+ assert attr.id == "attr1"
18
+ assert attr.title == "Attribute 1"
19
+ assert attr.source_column == "col_attr1"
20
+ assert attr.source_column_data_type == ColumnDataType.STRING.value
21
+ assert attr.tags == ["dataset_name"]
22
+ assert attr.description is None
23
+
24
+
25
+ def test_attribute_from_field_custom_tags_and_description():
26
+ field = CustomFieldDefinition(
19
27
  workspace_id="workspace1",
20
28
  dataset_id="ds1",
21
29
  custom_field_id="attr1",
@@ -23,79 +31,14 @@ def mock_custom_field_attribute():
23
31
  custom_field_type=CustomFieldType.ATTRIBUTE,
24
32
  custom_field_source_column="col_attr1",
25
33
  custom_field_source_column_data_type=ColumnDataType.STRING,
34
+ tags=["t1", "t2"],
35
+ description="Attr desc",
26
36
  )
27
-
28
-
29
- @pytest.fixture
30
- def mock_custom_field_fact():
31
- return CustomFieldDefinition(
32
- workspace_id="workspace1",
33
- dataset_id="ds1",
34
- custom_field_id="fact1",
35
- custom_field_name="Fact 1",
36
- custom_field_type=CustomFieldType.FACT,
37
- custom_field_source_column="col_fact1",
38
- custom_field_source_column_data_type=ColumnDataType.INT,
39
- )
40
-
41
-
42
- @pytest.fixture
43
- def mock_custom_field_date():
44
- return CustomFieldDefinition(
45
- workspace_id="workspace1",
46
- dataset_id="ds1",
47
- custom_field_id="date1",
48
- custom_field_name="Date 1",
49
- custom_field_type=CustomFieldType.DATE,
50
- custom_field_source_column="col_date1",
51
- custom_field_source_column_data_type=ColumnDataType.DATE,
52
- )
53
-
54
-
55
- @pytest.fixture
56
- def mock_dataset_definition():
57
- return CustomDatasetDefinition(
58
- workspace_id="workspace1",
59
- dataset_id="ds1",
60
- dataset_name="Dataset 1",
61
- dataset_source_table="table1",
62
- dataset_datasource_id="ds_source",
63
- dataset_source_sql=None,
64
- parent_dataset_reference="parent_ds",
65
- parent_dataset_reference_attribute_id="parent_attr",
66
- dataset_reference_source_column="ref_col",
67
- dataset_reference_source_column_data_type=ColumnDataType.STRING,
68
- workspace_data_filter_id="wdf1",
69
- workspace_data_filter_column_name="col1",
70
- )
71
-
72
-
73
- @pytest.fixture
74
- def mock_custom_dataset(
75
- mock_dataset_definition,
76
- mock_custom_field_attribute,
77
- mock_custom_field_fact,
78
- mock_custom_field_date,
79
- ):
80
- return CustomDataset(
81
- definition=mock_dataset_definition,
82
- custom_fields=[
83
- mock_custom_field_attribute,
84
- mock_custom_field_fact,
85
- mock_custom_field_date,
86
- ],
87
- )
88
-
89
-
90
- def test_attribute_from_field(mock_custom_field_attribute):
91
37
  attr = LdmExtensionDataProcessor._attribute_from_field(
92
- "dataset_name", mock_custom_field_attribute
38
+ "dataset_name", field
93
39
  )
94
- assert attr.id == "attr1"
95
- assert attr.title == "Attribute 1"
96
- assert attr.source_column == "col_attr1"
97
- assert attr.source_column_data_type == ColumnDataType.STRING.value
98
- assert attr.tags == ["dataset_name"]
40
+ assert attr.tags == ["t1", "t2"]
41
+ assert attr.description == "Attr desc"
99
42
 
100
43
 
101
44
  def test_fact_from_field(mock_custom_field_fact):
@@ -149,6 +92,20 @@ def test_get_sources_sql_only(mock_dataset_definition):
149
92
  assert sql.statement == "SELECT * FROM foo"
150
93
 
151
94
 
95
+ def test_datasets_to_ldm_dataset_tags_and_description(mock_dataset_definition):
96
+ mock_dataset_definition.dataset_tags = ["managed", "extra"]
97
+ mock_dataset_definition.dataset_description = "DS desc"
98
+ mock_dataset_definition.dataset_source_sql = "SELECT 1"
99
+ mock_dataset_definition.dataset_source_table = None
100
+ ds = CustomDataset(definition=mock_dataset_definition, custom_fields=[])
101
+ processor = LdmExtensionDataProcessor()
102
+ model = processor.datasets_to_ldm({"ds1": ds})
103
+ d = model.ldm.datasets[0]
104
+ assert d.description == "DS desc"
105
+ assert d.tags == ["managed", "extra"]
106
+ assert d.sql is not None
107
+
108
+
152
109
  def test_datasets_to_ldm(mock_custom_dataset):
153
110
  print(mock_custom_dataset)
154
111
  processor = LdmExtensionDataProcessor()