gooddata-pipelines 1.51.0__tar.gz → 1.52.1.dev1__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.

Potentially problematic release.


This version of gooddata-pipelines might be problematic. Click here for more details.

Files changed (148) hide show
  1. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/PKG-INFO +14 -10
  2. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/README.md +12 -8
  3. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/TODO.md +0 -5
  4. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/__init__.py +6 -0
  5. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/backup_input_processor.py +2 -3
  6. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/backup_manager.py +2 -2
  7. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/constants.py +4 -4
  8. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/user_data_filters/models/udf_models.py +8 -10
  9. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/user_data_filters/user_data_filters.py +2 -2
  10. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/models/permissions.py +3 -1
  11. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/models/user_groups.py +9 -1
  12. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/models/users.py +3 -1
  13. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/workspaces/models.py +1 -1
  14. gooddata_pipelines-1.52.1.dev1/gooddata_pipelines/provisioning/generic/config.py +118 -0
  15. gooddata_pipelines-1.52.1.dev1/gooddata_pipelines/provisioning/generic/provision.py +49 -0
  16. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/utils/utils.py +24 -15
  17. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/pyproject.toml +3 -2
  18. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/users/test_permissions.py +4 -4
  19. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/users/test_users.py +6 -6
  20. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/workspaces/test_workspace_data_filters.py +3 -3
  21. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/test_provisioning.py +105 -0
  22. gooddata_pipelines-1.52.1.dev1/tests/test_ldm_extension/test_models/__init__.py +1 -0
  23. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/test_ldm_extension/test_models/test_analytical_object.py +2 -3
  24. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/.gitignore +0 -0
  25. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/LICENSE.txt +0 -0
  26. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/Makefile +0 -0
  27. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/_version.py +0 -0
  28. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/api/__init__.py +0 -0
  29. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/api/exceptions.py +0 -0
  30. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/api/gooddata_api.py +0 -0
  31. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/api/gooddata_api_wrapper.py +0 -0
  32. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/api/gooddata_sdk.py +0 -0
  33. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/api/utils.py +0 -0
  34. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/__init__.py +0 -0
  35. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/csv_reader.py +0 -0
  36. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/models/__init__.py +0 -0
  37. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/models/input_type.py +0 -0
  38. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/models/storage.py +0 -0
  39. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/models/workspace_response.py +0 -0
  40. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/storage/__init__.py +0 -0
  41. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/storage/base_storage.py +0 -0
  42. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/storage/local_storage.py +0 -0
  43. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/backup_and_restore/storage/s3_storage.py +0 -0
  44. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/__init__.py +0 -0
  45. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/input_processor.py +0 -0
  46. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/input_validator.py +0 -0
  47. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/ldm_extension_manager.py +0 -0
  48. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/models/__init__.py +0 -0
  49. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/models/aliases.py +0 -0
  50. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/models/analytical_object.py +0 -0
  51. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/ldm_extension/models/custom_data_object.py +0 -0
  52. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/logger/__init__.py +0 -0
  53. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/logger/logger.py +0 -0
  54. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/__init__.py +0 -0
  55. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/assets/wdf_setting.json +0 -0
  56. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/__init__.py +0 -0
  57. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/user_data_filters/__init__.py +0 -0
  58. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/user_data_filters/models/__init__.py +0 -0
  59. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/__init__.py +0 -0
  60. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/models/__init__.py +0 -0
  61. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/permissions.py +0 -0
  62. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/user_groups.py +0 -0
  63. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/users/users.py +0 -0
  64. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/workspaces/__init__.py +0 -0
  65. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/workspaces/workspace.py +0 -0
  66. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_filters.py +0 -0
  67. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_parser.py +0 -0
  68. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_validator.py +0 -0
  69. {gooddata_pipelines-1.51.0/gooddata_pipelines/provisioning/utils → gooddata_pipelines-1.52.1.dev1/gooddata_pipelines/provisioning/generic}/__init__.py +0 -0
  70. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/provisioning.py +0 -0
  71. {gooddata_pipelines-1.51.0/tests → gooddata_pipelines-1.52.1.dev1/gooddata_pipelines/provisioning/utils}/__init__.py +0 -0
  72. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/utils/context_objects.py +0 -0
  73. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/provisioning/utils/exceptions.py +0 -0
  74. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/py.typed +0 -0
  75. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/utils/__init__.py +0 -0
  76. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/gooddata_pipelines/utils/rate_limiter.py +0 -0
  77. {gooddata_pipelines-1.51.0/tests/backup_and_restore → gooddata_pipelines-1.52.1.dev1/tests}/__init__.py +0 -0
  78. {gooddata_pipelines-1.51.0/tests/data → gooddata_pipelines-1.52.1.dev1/tests/backup_and_restore}/__init__.py +0 -0
  79. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/backup_and_restore/test_backup.py +0 -0
  80. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/backup_and_restore/test_backup_input_processor.py +0 -0
  81. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/conftest.py +0 -0
  82. {gooddata_pipelines-1.51.0/tests/data/backup → gooddata_pipelines-1.52.1.dev1/tests/data}/__init__.py +0 -0
  83. {gooddata_pipelines-1.51.0/tests/panther → gooddata_pipelines-1.52.1.dev1/tests/data/backup}/__init__.py +0 -0
  84. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_conf.yaml +0 -0
  85. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  86. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  87. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  88. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  89. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/analytics_model/metrics/.gitkeep +0 -0
  90. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  91. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid1/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid1/ldm/datasets/test.yaml +0 -0
  92. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  93. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  94. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  95. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  96. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  97. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/analytics_model/metrics/.gitkeep +0 -0
  98. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  99. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/ldm/datasets/.gitkeep +0 -0
  100. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid2/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid2/ldm/date_instances/.gitkeep +0 -0
  101. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  102. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  103. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  104. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  105. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/analytics_model/metrics/.gitkeep +0 -0
  106. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/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
  107. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/ldm/datasets/.gitkeep +0 -0
  108. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/ldm/date_instances/.gitkeep +0 -0
  109. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_exports/services/wsid3/20230713-132759-1_3_1_dev5/gooddata_layouts/services/workspaces/wsid3/user_data_filters/.gitkeep +0 -0
  110. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/backup/test_local_conf.yaml +0 -0
  111. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/custom_fields/response_get_all_dashboards.json +0 -0
  112. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/custom_fields/response_get_all_metrics.json +0 -0
  113. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/custom_fields/response_get_all_visualizations.json +0 -0
  114. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/mock_responses.py +0 -0
  115. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/profiles.yaml +0 -0
  116. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/permissions/existing_upstream_permissions.json +0 -0
  117. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/permissions/permissions_expected_full_load.json +0 -0
  118. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/permissions/permissions_expected_incremental_load.json +0 -0
  119. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/permissions/permissions_input_full_load.json +0 -0
  120. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/permissions/permissions_input_incremental_load.json +0 -0
  121. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/existing_upstream_users.json +0 -0
  122. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/profile_response_content.json +0 -0
  123. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_expected_full_load.json +0 -0
  124. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_expected_incremental_load.json +0 -0
  125. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_input_full_load.json +0 -0
  126. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_input_full_load_modifies_protected_user.json +0 -0
  127. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_input_incremental_load.json +0 -0
  128. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_input_incremental_load_deletes_protected_user.json +0 -0
  129. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/data/provisioning/entities/users/users_input_incremental_load_modifies_protected_user.json +0 -0
  130. {gooddata_pipelines-1.51.0/tests/provisioning → gooddata_pipelines-1.52.1.dev1/tests/panther}/__init__.py +0 -0
  131. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/panther/test_api_wrapper.py +0 -0
  132. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/panther/test_sdk_wrapper.py +0 -0
  133. {gooddata_pipelines-1.51.0/tests/provisioning/entities → gooddata_pipelines-1.52.1.dev1/tests/provisioning}/__init__.py +0 -0
  134. {gooddata_pipelines-1.51.0/tests/provisioning/entities/users → gooddata_pipelines-1.52.1.dev1/tests/provisioning/entities}/__init__.py +0 -0
  135. {gooddata_pipelines-1.51.0/tests/provisioning/entities/workspaces → gooddata_pipelines-1.52.1.dev1/tests/provisioning/entities/users}/__init__.py +0 -0
  136. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/users/test_user_groups.py +0 -0
  137. {gooddata_pipelines-1.51.0/tests/test_ldm_extension → gooddata_pipelines-1.52.1.dev1/tests/provisioning/entities/workspaces}/__init__.py +0 -0
  138. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/workspaces/test_provisioning.py +0 -0
  139. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/workspaces/test_workspace.py +0 -0
  140. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/workspaces/test_workspace_data_parser.py +0 -0
  141. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/provisioning/entities/workspaces/test_workspace_data_validator.py +0 -0
  142. {gooddata_pipelines-1.51.0/tests/test_ldm_extension/test_models → gooddata_pipelines-1.52.1.dev1/tests/test_ldm_extension}/__init__.py +0 -0
  143. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/test_ldm_extension/test_input_processor.py +0 -0
  144. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/test_ldm_extension/test_input_validator.py +0 -0
  145. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/test_ldm_extension/test_ldm_extension_manager.py +0 -0
  146. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/test_ldm_extension/test_models/test_custom_data_object.py +0 -0
  147. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tests/utils/test_rate_limiter.py +0 -0
  148. {gooddata_pipelines-1.51.0 → gooddata_pipelines-1.52.1.dev1}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gooddata-pipelines
3
- Version: 1.51.0
3
+ Version: 1.52.1.dev1
4
4
  Summary: GoodData Cloud lifecycle automation pipelines
5
5
  Author-email: GoodData <support@gooddata.com>
6
6
  License: MIT
@@ -8,7 +8,7 @@ License-File: LICENSE.txt
8
8
  Requires-Python: >=3.10
9
9
  Requires-Dist: boto3-stubs<2.0.0,>=1.39.3
10
10
  Requires-Dist: boto3<2.0.0,>=1.39.3
11
- Requires-Dist: gooddata-sdk~=1.51.0
11
+ Requires-Dist: gooddata-sdk~=1.52.1.dev1
12
12
  Requires-Dist: pydantic<3.0.0,>=2.11.3
13
13
  Requires-Dist: requests<3.0.0,>=2.32.3
14
14
  Requires-Dist: types-pyyaml<7.0.0,>=6.0.12.20250326
@@ -45,33 +45,37 @@ The provisioning module exposes _Provisioner_ classes reflecting the different e
45
45
 
46
46
  ```python
47
47
  import os
48
+ import logging
49
+
48
50
  from csv import DictReader
49
51
  from pathlib import Path
50
52
 
51
53
  # Import the Entity Provisioner class and corresponding model from gooddata_pipelines library
52
54
  from gooddata_pipelines import UserFullLoad, UserProvisioner
53
- from gooddata_pipelines.logger.logger import LogObserver
54
-
55
- # Optionally, subscribe a standard Python logger to the LogObserver
56
- import logging
57
- logger = logging.getLogger(__name__)
58
- LogObserver().subscribe(logger)
59
55
 
60
56
  # Create the Provisioner instance - you can also create the instance from a GDC yaml profile
61
57
  provisioner = UserProvisioner(
62
58
  host=os.environ["GDC_HOSTNAME"], token=os.environ["GDC_AUTH_TOKEN"]
63
59
  )
64
60
 
61
+ # Optional: set up logging and subscribe to logs emitted by the provisioner
62
+ logging.basicConfig(level=logging.INFO)
63
+ logger = logging.getLogger(__name__)
64
+ provisioner.logger.subscribe(logger)
65
+
65
66
  # Load your data from your data source
66
67
  source_data_path: Path = Path("path/to/some.csv")
67
68
  source_data_reader = DictReader(source_data_path.read_text().splitlines())
68
69
  source_data = [row for row in source_data_reader]
69
70
 
70
- # Validate your input data with
71
+ # Validate your input data
71
72
  full_load_data: list[UserFullLoad] = UserFullLoad.from_list_of_dicts(
72
73
  source_data
73
74
  )
75
+
76
+ # Run the provisioning
74
77
  provisioner.full_load(full_load_data)
78
+
75
79
  ```
76
80
 
77
81
  ## Bugs & Requests
@@ -81,5 +85,5 @@ or request features.
81
85
 
82
86
  ## Changelog
83
87
 
84
- See [Github releases](https://github.com/gooddata/gooddata-python-sdk/releases) for released versions
88
+ See [Github releases](https://github.com/gooddata/gooddata-python-sdk/releases) for released versions
85
89
  and a list of changes.
@@ -28,33 +28,37 @@ The provisioning module exposes _Provisioner_ classes reflecting the different e
28
28
 
29
29
  ```python
30
30
  import os
31
+ import logging
32
+
31
33
  from csv import DictReader
32
34
  from pathlib import Path
33
35
 
34
36
  # Import the Entity Provisioner class and corresponding model from gooddata_pipelines library
35
37
  from gooddata_pipelines import UserFullLoad, UserProvisioner
36
- from gooddata_pipelines.logger.logger import LogObserver
37
-
38
- # Optionally, subscribe a standard Python logger to the LogObserver
39
- import logging
40
- logger = logging.getLogger(__name__)
41
- LogObserver().subscribe(logger)
42
38
 
43
39
  # Create the Provisioner instance - you can also create the instance from a GDC yaml profile
44
40
  provisioner = UserProvisioner(
45
41
  host=os.environ["GDC_HOSTNAME"], token=os.environ["GDC_AUTH_TOKEN"]
46
42
  )
47
43
 
44
+ # Optional: set up logging and subscribe to logs emitted by the provisioner
45
+ logging.basicConfig(level=logging.INFO)
46
+ logger = logging.getLogger(__name__)
47
+ provisioner.logger.subscribe(logger)
48
+
48
49
  # Load your data from your data source
49
50
  source_data_path: Path = Path("path/to/some.csv")
50
51
  source_data_reader = DictReader(source_data_path.read_text().splitlines())
51
52
  source_data = [row for row in source_data_reader]
52
53
 
53
- # Validate your input data with
54
+ # Validate your input data
54
55
  full_load_data: list[UserFullLoad] = UserFullLoad.from_list_of_dicts(
55
56
  source_data
56
57
  )
58
+
59
+ # Run the provisioning
57
60
  provisioner.full_load(full_load_data)
61
+
58
62
  ```
59
63
 
60
64
  ## Bugs & Requests
@@ -64,5 +68,5 @@ or request features.
64
68
 
65
69
  ## Changelog
66
70
 
67
- See [Github releases](https://github.com/gooddata/gooddata-python-sdk/releases) for released versions
71
+ See [Github releases](https://github.com/gooddata/gooddata-python-sdk/releases) for released versions
68
72
  and a list of changes.
@@ -10,15 +10,10 @@ A list of outstanding tasks, features, or technical debt to be addressed in this
10
10
 
11
11
  - [ ] Integrate with GoodDataApiClient
12
12
  - [ ] Consider replacing the SdkMethods wrapper with direct calls to the SDK methods
13
- - [ ] Consider using orjson library instead of json to load test data
14
13
  - [ ] Cleanup custom exceptions
15
14
  - [ ] Improve test coverage. Write missing unit tests for legacy code (e.g., user data filters)
16
15
 
17
16
  ## Documentation
18
17
 
19
18
  - [ ] Improve package README
20
- - [ ] Workspace provisioning
21
- - [ ] User provisioning
22
- - [ ] User group provisioning
23
- - [ ] Permission provisioning
24
19
  - [ ] User data filter provisioning
@@ -51,6 +51,10 @@ from .provisioning.entities.workspaces.models import (
51
51
  )
52
52
  from .provisioning.entities.workspaces.workspace import WorkspaceProvisioner
53
53
 
54
+ # -------- Generic Provisioning --------
55
+ from .provisioning.generic.config import WorkflowType
56
+ from .provisioning.generic.provision import provision
57
+
54
58
  __all__ = [
55
59
  "BackupManager",
56
60
  "BackupRestoreConfig",
@@ -79,5 +83,7 @@ __all__ = [
79
83
  "CustomFieldDefinition",
80
84
  "ColumnDataType",
81
85
  "CustomFieldType",
86
+ "provision",
87
+ "WorkflowType",
82
88
  "__version__",
83
89
  ]
@@ -1,7 +1,6 @@
1
1
  # (C) 2025 GoodData Corporation
2
2
 
3
- from dataclasses import dataclass
4
-
3
+ import attrs
5
4
  import requests
6
5
 
7
6
  from gooddata_pipelines.api import GoodDataApi
@@ -46,7 +45,7 @@ class BackupInputProcessor:
46
45
  )
47
46
  self.all_workspaces_endpoint = f"{self.base_workspace_endpoint}?page=0&size={self.page_size}&sort=name,asc&metaInclude=page"
48
47
 
49
- @dataclass
48
+ @attrs.define
50
49
  class _ProcessDataOutput:
51
50
  workspace_ids: list[str]
52
51
  sub_parents: list[str] | None = None
@@ -6,10 +6,10 @@ import shutil
6
6
  import tempfile
7
7
  import time
8
8
  import traceback
9
- from dataclasses import dataclass
10
9
  from pathlib import Path
11
10
  from typing import Any, Type
12
11
 
12
+ import attrs
13
13
  import requests
14
14
  import yaml
15
15
  from gooddata_sdk.utils import PROFILES_FILE_PATH, profile_content
@@ -40,7 +40,7 @@ from gooddata_pipelines.logger import LogObserver
40
40
  from gooddata_pipelines.utils.rate_limiter import RateLimiter
41
41
 
42
42
 
43
- @dataclass
43
+ @attrs.define
44
44
  class BackupBatch:
45
45
  list_of_ids: list[str]
46
46
 
@@ -1,11 +1,11 @@
1
1
  # (C) 2025 GoodData Corporation
2
2
  import datetime
3
- from dataclasses import dataclass
4
3
 
4
+ import attrs
5
5
  from gooddata_sdk._version import __version__ as sdk_version
6
6
 
7
7
 
8
- @dataclass(frozen=True)
8
+ @attrs.frozen
9
9
  class DirNames:
10
10
  """
11
11
  Folder names used in the SDK backup process:
@@ -21,14 +21,14 @@ class DirNames:
21
21
  UDF = "user_data_filters"
22
22
 
23
23
 
24
- @dataclass(frozen=True)
24
+ @attrs.frozen
25
25
  class ApiDefaults:
26
26
  DEFAULT_PAGE_SIZE = 100
27
27
  DEFAULT_BATCH_SIZE = 100
28
28
  DEFAULT_API_CALLS_PER_SECOND = 1.0
29
29
 
30
30
 
31
- @dataclass(frozen=True)
31
+ @attrs.frozen
32
32
  class BackupSettings(ApiDefaults):
33
33
  MAX_RETRIES = 3
34
34
  RETRY_DELAY = 5 # seconds
@@ -2,31 +2,29 @@
2
2
 
3
3
  """This module defines data models for user data filters in a GoodData workspace."""
4
4
 
5
- # TODO: consider using attrs instead of dataclasses for these models. Dataclasses
6
- # have different functionality per Python version (not package version).
5
+ import attrs
6
+ from pydantic import BaseModel, ConfigDict
7
7
 
8
- from dataclasses import dataclass, field
9
8
 
10
-
11
- @dataclass
9
+ @attrs.define
12
10
  class UserDataFilterGroup:
13
11
  udf_id: str
14
12
  udf_values: list[str]
15
13
 
16
14
 
17
- @dataclass
15
+ @attrs.define
18
16
  class WorkspaceUserDataFilters:
19
17
  workspace_id: str
20
- user_data_filters: list["UserDataFilterGroup"] = field(default_factory=list)
18
+ user_data_filters: list["UserDataFilterGroup"] = attrs.field(factory=list)
19
+
21
20
 
21
+ class UserDataFilterFullLoad(BaseModel):
22
+ model_config = ConfigDict(extra="forbid")
22
23
 
23
- @dataclass
24
- class UserDataFilterFullLoad:
25
24
  workspace_id: str
26
25
  udf_id: str
27
26
  udf_value: str
28
27
 
29
28
 
30
- @dataclass
31
29
  class UserDataFilterIncrementalLoad(UserDataFilterFullLoad):
32
30
  is_active: bool
@@ -50,6 +50,8 @@ class UserDataFilterProvisioner(
50
50
  ldm_column_name: str = ""
51
51
  maql_column_name: str = ""
52
52
 
53
+ FULL_LOAD_TYPE = UserDataFilterFullLoad
54
+
53
55
  def set_ldm_column_name(self, ldm_column_name: str) -> None:
54
56
  """Set the LDM column name for user data filters.
55
57
 
@@ -214,8 +216,6 @@ class UserDataFilterProvisioner(
214
216
  )
215
217
  self._create_user_data_filters(grouped_db_user_data_filters)
216
218
 
217
- self.logger.info("User data filters provisioning completed")
218
-
219
219
  def _provision_incremental_load(self) -> None:
220
220
  """Provision user data filters in GoodData workspaces."""
221
221
  raise NotImplementedError("Not implemented yet.")
@@ -9,7 +9,7 @@ from gooddata_sdk.catalog.permission.declarative_model.permission import (
9
9
  CatalogDeclarativeSingleWorkspacePermission,
10
10
  CatalogDeclarativeWorkspacePermissions,
11
11
  )
12
- from pydantic import BaseModel
12
+ from pydantic import BaseModel, ConfigDict
13
13
 
14
14
  from gooddata_pipelines.provisioning.utils.exceptions import BaseUserException
15
15
 
@@ -23,6 +23,8 @@ class EntityType(str, Enum):
23
23
 
24
24
 
25
25
  class BasePermission(BaseModel):
26
+ model_config = ConfigDict(extra="forbid")
27
+
26
28
  permission: str
27
29
  workspace_id: str
28
30
  entity_id: str
@@ -1,9 +1,17 @@
1
1
  # (C) 2025 GoodData Corporation
2
2
 
3
- from pydantic import BaseModel, Field, ValidationInfo, field_validator
3
+ from pydantic import (
4
+ BaseModel,
5
+ ConfigDict,
6
+ Field,
7
+ ValidationInfo,
8
+ field_validator,
9
+ )
4
10
 
5
11
 
6
12
  class UserGroupBase(BaseModel):
13
+ model_config = ConfigDict(extra="forbid")
14
+
7
15
  user_group_id: str
8
16
  user_group_name: str
9
17
  parent_user_groups: list[str] = Field(default_factory=list)
@@ -3,7 +3,7 @@
3
3
  from typing import Any
4
4
 
5
5
  from gooddata_sdk.catalog.user.entity_model.user import CatalogUser
6
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, ConfigDict, Field
7
7
 
8
8
 
9
9
  class UserProfile(BaseModel):
@@ -18,6 +18,8 @@ class UserProfile(BaseModel):
18
18
  class BaseUser(BaseModel):
19
19
  """Base class containing shared user fields and functionality."""
20
20
 
21
+ model_config = ConfigDict(extra="forbid")
22
+
21
23
  user_id: str
22
24
  firstname: str | None
23
25
  lastname: str | None
@@ -22,7 +22,7 @@ class WorkspaceDataMaps:
22
22
 
23
23
 
24
24
  class WorkspaceBase(BaseModel):
25
- model_config = ConfigDict(coerce_numbers_to_str=True)
25
+ model_config = ConfigDict(coerce_numbers_to_str=True, extra="forbid")
26
26
 
27
27
  parent_id: str
28
28
  workspace_id: str
@@ -0,0 +1,118 @@
1
+ # (C) 2025 GoodData Corporation
2
+
3
+ from enum import Enum
4
+ from typing import Type, TypeAlias
5
+
6
+ import attrs
7
+
8
+ from gooddata_pipelines.provisioning.entities.users.models.permissions import (
9
+ PermissionFullLoad,
10
+ PermissionIncrementalLoad,
11
+ )
12
+ from gooddata_pipelines.provisioning.entities.users.models.user_groups import (
13
+ UserGroupFullLoad,
14
+ UserGroupIncrementalLoad,
15
+ )
16
+ from gooddata_pipelines.provisioning.entities.users.models.users import (
17
+ UserFullLoad,
18
+ UserIncrementalLoad,
19
+ )
20
+ from gooddata_pipelines.provisioning.entities.users.permissions import (
21
+ PermissionProvisioner,
22
+ )
23
+ from gooddata_pipelines.provisioning.entities.users.user_groups import (
24
+ UserGroupProvisioner,
25
+ )
26
+ from gooddata_pipelines.provisioning.entities.users.users import UserProvisioner
27
+ from gooddata_pipelines.provisioning.entities.workspaces.models import (
28
+ WorkspaceFullLoad,
29
+ WorkspaceIncrementalLoad,
30
+ )
31
+ from gooddata_pipelines.provisioning.entities.workspaces.workspace import (
32
+ WorkspaceProvisioner,
33
+ )
34
+
35
+ ValidationModel: TypeAlias = (
36
+ PermissionFullLoad
37
+ | PermissionIncrementalLoad
38
+ | UserFullLoad
39
+ | UserIncrementalLoad
40
+ | UserGroupFullLoad
41
+ | UserGroupIncrementalLoad
42
+ | WorkspaceFullLoad
43
+ | WorkspaceIncrementalLoad
44
+ )
45
+
46
+ Provisioner: TypeAlias = (
47
+ PermissionProvisioner
48
+ | UserProvisioner
49
+ | UserGroupProvisioner
50
+ | WorkspaceProvisioner
51
+ )
52
+
53
+
54
+ class LoadType(str, Enum):
55
+ FULL = "full"
56
+ INCREMENTAL = "incremental"
57
+
58
+
59
+ class WorkflowType(str, Enum):
60
+ WORKSPACE_FULL_LOAD = "workspace_full_load"
61
+ WORKSPACE_INCREMENTAL_LOAD = "workspace_incremental_load"
62
+ USER_FULL_LOAD = "user_full_load"
63
+ USER_INCREMENTAL_LOAD = "user_incremental_load"
64
+ USER_GROUP_FULL_LOAD = "user_group_full_load"
65
+ USER_GROUP_INCREMENTAL_LOAD = "user_group_incremental_load"
66
+ PERMISSION_FULL_LOAD = "permission_full_load"
67
+ PERMISSION_INCREMENTAL_LOAD = "permission_incremental_load"
68
+
69
+
70
+ @attrs.define
71
+ class ProvisioningConfig:
72
+ validation_model: Type[ValidationModel]
73
+ provisioner_class: Type[Provisioner]
74
+ load_type: LoadType
75
+
76
+
77
+ PROVISIONING_CONFIG = {
78
+ WorkflowType.WORKSPACE_FULL_LOAD: ProvisioningConfig(
79
+ validation_model=WorkspaceFullLoad,
80
+ provisioner_class=WorkspaceProvisioner,
81
+ load_type=LoadType.FULL,
82
+ ),
83
+ WorkflowType.WORKSPACE_INCREMENTAL_LOAD: ProvisioningConfig(
84
+ validation_model=WorkspaceIncrementalLoad,
85
+ provisioner_class=WorkspaceProvisioner,
86
+ load_type=LoadType.INCREMENTAL,
87
+ ),
88
+ WorkflowType.USER_FULL_LOAD: ProvisioningConfig(
89
+ validation_model=UserFullLoad,
90
+ provisioner_class=UserProvisioner,
91
+ load_type=LoadType.FULL,
92
+ ),
93
+ WorkflowType.USER_INCREMENTAL_LOAD: ProvisioningConfig(
94
+ validation_model=UserIncrementalLoad,
95
+ provisioner_class=UserProvisioner,
96
+ load_type=LoadType.INCREMENTAL,
97
+ ),
98
+ WorkflowType.USER_GROUP_FULL_LOAD: ProvisioningConfig(
99
+ validation_model=UserGroupFullLoad,
100
+ provisioner_class=UserGroupProvisioner,
101
+ load_type=LoadType.FULL,
102
+ ),
103
+ WorkflowType.USER_GROUP_INCREMENTAL_LOAD: ProvisioningConfig(
104
+ validation_model=UserGroupIncrementalLoad,
105
+ provisioner_class=UserGroupProvisioner,
106
+ load_type=LoadType.INCREMENTAL,
107
+ ),
108
+ WorkflowType.PERMISSION_FULL_LOAD: ProvisioningConfig(
109
+ validation_model=PermissionFullLoad,
110
+ provisioner_class=PermissionProvisioner,
111
+ load_type=LoadType.FULL,
112
+ ),
113
+ WorkflowType.PERMISSION_INCREMENTAL_LOAD: ProvisioningConfig(
114
+ validation_model=PermissionIncrementalLoad,
115
+ provisioner_class=PermissionProvisioner,
116
+ load_type=LoadType.INCREMENTAL,
117
+ ),
118
+ }
@@ -0,0 +1,49 @@
1
+ # (C) 2025 GoodData Corporation
2
+
3
+ from typing import Any
4
+
5
+ from gooddata_pipelines.logger import LoggerLike
6
+ from gooddata_pipelines.provisioning.generic.config import (
7
+ PROVISIONING_CONFIG,
8
+ LoadType,
9
+ WorkflowType,
10
+ )
11
+
12
+
13
+ def provision(
14
+ data: list[dict[str, Any]],
15
+ workflow_type: WorkflowType,
16
+ host: str,
17
+ token: str,
18
+ logger: LoggerLike | None = None,
19
+ ) -> None:
20
+ """Generic provisioning function accepting raw data and workflow type.
21
+
22
+ The function will validate data based on the selected workflow type and run
23
+ the corresponding provisioning in full or incremental mode.
24
+
25
+ Args:
26
+ data: List of dictionaries containing the data to be provisioned.
27
+ workflow_type: The type of workflow to run.
28
+ host: The host of the GoodData platform.
29
+ token: The token for the GoodData platform.
30
+ logger: The logger to use for logging.
31
+ """
32
+
33
+ if workflow_type not in PROVISIONING_CONFIG:
34
+ raise ValueError(f"Invalid workflow type: {workflow_type}")
35
+
36
+ config = PROVISIONING_CONFIG[workflow_type]
37
+
38
+ provisioner = config.provisioner_class.create(host, token)
39
+ validated_data: list = [config.validation_model(**item) for item in data]
40
+
41
+ if logger:
42
+ provisioner.logger.subscribe(logger)
43
+
44
+ if config.load_type == LoadType.FULL:
45
+ provisioner.full_load(validated_data)
46
+ elif config.load_type == LoadType.INCREMENTAL:
47
+ provisioner.incremental_load(validated_data)
48
+ else:
49
+ raise ValueError(f"Invalid load type: {config.load_type}")
@@ -2,6 +2,8 @@
2
2
 
3
3
  """Module for utilities used in GoodData Pipelines provisioning."""
4
4
 
5
+ from typing import Any, cast
6
+
5
7
  import attrs
6
8
  from requests import Response
7
9
 
@@ -11,9 +13,8 @@ class AttributesMixin:
11
13
  Mixin class to provide a method for getting attributes of an object which may or may not exist.
12
14
  """
13
15
 
14
- @staticmethod
15
16
  def get_attrs(
16
- *objects: object, overrides: dict[str, str] | None = None
17
+ self, *objects: object, overrides: dict[str, str] | None = None
17
18
  ) -> dict[str, str]:
18
19
  """
19
20
  Returns a dictionary of attributes from the given objects.
@@ -27,11 +28,11 @@ class AttributesMixin:
27
28
  """
28
29
  # TODO: This might not work great with nested objects, values which are lists of objects etc.
29
30
  # If we care about parsing the logs back from the string, we should consider some other approach
30
- attrs: dict[str, str] = {}
31
+ attributes: dict[str, str] = {}
31
32
  for context_object in objects:
32
33
  if isinstance(context_object, Response):
33
34
  # for request.Response objects, keys need to be renamed to match the log schema
34
- attrs.update(
35
+ attributes.update(
35
36
  {
36
37
  "http_status": str(context_object.status_code),
37
38
  "http_method": getattr(
@@ -42,23 +43,31 @@ class AttributesMixin:
42
43
  ),
43
44
  }
44
45
  )
46
+ elif attrs.has(type(context_object)):
47
+ for key, value in attrs.asdict(
48
+ cast(attrs.AttrsInstance, context_object)
49
+ ).items():
50
+ self._add_to_dict(attributes, key, value)
45
51
  else:
46
52
  # Generic handling for other objects
47
53
  for key, value in context_object.__dict__.items():
48
- if value is None:
49
- continue
50
-
51
- if isinstance(value, list):
52
- attrs[key] = ", ".join(
53
- str(list_item) for list_item in value
54
- )
55
- else:
56
- attrs[key] = str(value)
54
+ self._add_to_dict(attributes, key, value)
57
55
 
58
56
  if overrides:
59
- attrs.update(overrides)
57
+ attributes.update(overrides)
58
+
59
+ return attributes
60
+
61
+ def _add_to_dict(
62
+ self, attributes: dict[str, str], key: str, value: Any
63
+ ) -> None:
64
+ if value is None:
65
+ return
60
66
 
61
- return attrs
67
+ if isinstance(value, list):
68
+ attributes[key] = ", ".join(str(list_item) for list_item in value)
69
+ else:
70
+ attributes[key] = str(value)
62
71
 
63
72
 
64
73
  @attrs.define
@@ -1,7 +1,7 @@
1
1
  # (C) 2025 GoodData Corporation
2
2
  [project]
3
3
  name = "gooddata-pipelines"
4
- version = "1.51.0"
4
+ version = "1.52.1.dev1"
5
5
  description = "GoodData Cloud lifecycle automation pipelines"
6
6
  authors = [{ name = "GoodData", email = "support@gooddata.com" }]
7
7
  license = { text = "MIT" }
@@ -11,7 +11,7 @@ dependencies = [
11
11
  "pydantic (>=2.11.3,<3.0.0)",
12
12
  "requests (>=2.32.3,<3.0.0)",
13
13
  "types-requests (>=2.32.0,<3.0.0)",
14
- "gooddata-sdk~=1.51.0",
14
+ "gooddata-sdk~=1.52.1.dev1",
15
15
  "boto3 (>=1.39.3,<2.0.0)",
16
16
  "boto3-stubs (>=1.39.3,<2.0.0)",
17
17
  "types-pyyaml (>=6.0.12.20250326,<7.0.0)"
@@ -33,6 +33,7 @@ moto = ">=5.1.6,<6.0.0"
33
33
  pytest = ">=8.3.5,<9.0.0"
34
34
  pytest-mock = ">=3.14.0,<4.0.0"
35
35
  ruff = ">=0.11.2,<0.12.0"
36
+ orjson = "^3.11.3"
36
37
 
37
38
  [build-system]
38
39
  requires = ["hatchling"]
@@ -1,7 +1,7 @@
1
1
  # (C) 2025 GoodData Corporation
2
- import json
3
2
  from typing import Literal
4
3
 
4
+ import orjson
5
5
  import pytest
6
6
  from gooddata_api_client.exceptions import ( # type: ignore[import]
7
7
  NotFoundException,
@@ -455,7 +455,7 @@ def test_permission_provisioner(
455
455
  f"{TEST_DATA_SUBDIR}/existing_upstream_permissions.json"
456
456
  )
457
457
  with open(EXISTING_UPSTREAM_PERMISSIONS_PATH, "r") as f:
458
- raw_existing_upstream_permissions = json.load(f)
458
+ raw_existing_upstream_permissions = orjson.loads(f.read())
459
459
 
460
460
  existing_upstream_permissions = parse_expected_permissions(
461
461
  raw_existing_upstream_permissions
@@ -477,11 +477,11 @@ def test_permission_provisioner(
477
477
 
478
478
  # Load source data
479
479
  with open(f"{TEST_DATA_SUBDIR}/{source_data_path}", "r") as f:
480
- source_data = json.load(f)
480
+ source_data = orjson.loads(f.read())
481
481
 
482
482
  # Load and parse expected data
483
483
  with open(f"{TEST_DATA_SUBDIR}/{expected_data_path}", "r") as f:
484
- raw_expected_result = json.load(f)
484
+ raw_expected_result = orjson.loads(f.read())
485
485
 
486
486
  expected_result = parse_expected_permissions(raw_expected_result)
487
487