gooddata-pipelines 1.52.1.dev1__tar.gz → 1.52.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.

Potentially problematic release.


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

Files changed (161) hide show
  1. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/PKG-INFO +6 -5
  2. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/README.md +4 -3
  3. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/__init__.py +6 -0
  4. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/api/gooddata_api.py +27 -0
  5. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/backup_manager.py +6 -61
  6. gooddata_pipelines-1.52.1.dev3/gooddata_pipelines/backup_and_restore/base_manager.py +73 -0
  7. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/constants.py +5 -4
  8. gooddata_pipelines-1.52.1.dev3/gooddata_pipelines/backup_and_restore/models/storage.py +156 -0
  9. gooddata_pipelines-1.52.1.dev3/gooddata_pipelines/backup_and_restore/restore_manager.py +266 -0
  10. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/storage/base_storage.py +11 -0
  11. gooddata_pipelines-1.52.1.dev3/gooddata_pipelines/backup_and_restore/storage/local_storage.py +48 -0
  12. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/storage/s3_storage.py +25 -2
  13. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/utils/utils.py +7 -4
  14. gooddata_pipelines-1.52.1.dev3/gooddata_pipelines/utils/decorators.py +30 -0
  15. gooddata_pipelines-1.52.1.dev3/gooddata_pipelines/utils/file_utils.py +63 -0
  16. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/pyproject.toml +2 -2
  17. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/backup_and_restore/test_backup.py +5 -2
  18. gooddata_pipelines-1.52.1.dev3/tests/backup_and_restore/test_restore.py +346 -0
  19. gooddata_pipelines-1.52.1.dev3/tests/data/restore/test_conf.yaml +6 -0
  20. gooddata_pipelines-1.52.1.dev3/tests/data/restore/test_udf_root/filter1.yaml +7 -0
  21. gooddata_pipelines-1.52.1.dev3/tests/data/restore/test_udf_root/filter2.yaml +7 -0
  22. gooddata_pipelines-1.52.1.dev3/tests/data/restore/test_udf_root/user_data_filters/filter1.yaml +7 -0
  23. gooddata_pipelines-1.52.1.dev3/tests/data/restore/test_udf_root/user_data_filters/filter2.yaml +7 -0
  24. gooddata_pipelines-1.52.1.dev3/tests/utils/test_decorators.py +40 -0
  25. gooddata_pipelines-1.52.1.dev1/gooddata_pipelines/backup_and_restore/models/storage.py +0 -98
  26. gooddata_pipelines-1.52.1.dev1/gooddata_pipelines/backup_and_restore/storage/local_storage.py +0 -37
  27. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/.gitignore +0 -0
  28. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/LICENSE.txt +0 -0
  29. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/Makefile +0 -0
  30. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/TODO.md +0 -0
  31. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/_version.py +0 -0
  32. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/api/__init__.py +0 -0
  33. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/api/exceptions.py +0 -0
  34. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/api/gooddata_api_wrapper.py +0 -0
  35. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/api/gooddata_sdk.py +0 -0
  36. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/api/utils.py +0 -0
  37. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/__init__.py +0 -0
  38. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/backup_input_processor.py +0 -0
  39. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/csv_reader.py +0 -0
  40. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/models/__init__.py +0 -0
  41. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/models/input_type.py +0 -0
  42. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/models/workspace_response.py +0 -0
  43. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/backup_and_restore/storage/__init__.py +0 -0
  44. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/__init__.py +0 -0
  45. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/input_processor.py +0 -0
  46. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/input_validator.py +0 -0
  47. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/ldm_extension_manager.py +0 -0
  48. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/models/__init__.py +0 -0
  49. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/models/aliases.py +0 -0
  50. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/models/analytical_object.py +0 -0
  51. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/ldm_extension/models/custom_data_object.py +0 -0
  52. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/logger/__init__.py +0 -0
  53. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/logger/logger.py +0 -0
  54. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/__init__.py +0 -0
  55. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/assets/wdf_setting.json +0 -0
  56. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/__init__.py +0 -0
  57. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/user_data_filters/__init__.py +0 -0
  58. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/user_data_filters/models/__init__.py +0 -0
  59. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/user_data_filters/models/udf_models.py +0 -0
  60. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/user_data_filters/user_data_filters.py +0 -0
  61. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/__init__.py +0 -0
  62. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/models/__init__.py +0 -0
  63. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/models/permissions.py +0 -0
  64. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/models/user_groups.py +0 -0
  65. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/models/users.py +0 -0
  66. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/permissions.py +0 -0
  67. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/user_groups.py +0 -0
  68. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/users/users.py +0 -0
  69. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/workspaces/__init__.py +0 -0
  70. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/workspaces/models.py +0 -0
  71. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/workspaces/workspace.py +0 -0
  72. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_filters.py +0 -0
  73. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_parser.py +0 -0
  74. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/entities/workspaces/workspace_data_validator.py +0 -0
  75. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/generic/__init__.py +0 -0
  76. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/generic/config.py +0 -0
  77. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/generic/provision.py +0 -0
  78. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/provisioning.py +0 -0
  79. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/utils/__init__.py +0 -0
  80. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/utils/context_objects.py +0 -0
  81. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/provisioning/utils/exceptions.py +0 -0
  82. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/py.typed +0 -0
  83. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/utils/__init__.py +0 -0
  84. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/gooddata_pipelines/utils/rate_limiter.py +0 -0
  85. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/__init__.py +0 -0
  86. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/backup_and_restore/__init__.py +0 -0
  87. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/backup_and_restore/test_backup_input_processor.py +0 -0
  88. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/conftest.py +0 -0
  89. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/__init__.py +0 -0
  90. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/backup/__init__.py +0 -0
  91. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/backup/test_conf.yaml +0 -0
  92. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  93. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  94. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  95. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  96. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  97. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  98. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  99. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  100. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  101. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  102. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  103. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  104. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  105. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  106. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  107. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  108. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  109. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  110. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  111. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  112. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  113. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  114. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  115. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  116. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.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
  117. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/backup/test_local_conf.yaml +0 -0
  118. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/custom_fields/response_get_all_dashboards.json +0 -0
  119. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/custom_fields/response_get_all_metrics.json +0 -0
  120. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/custom_fields/response_get_all_visualizations.json +0 -0
  121. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/mock_responses.py +0 -0
  122. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/profiles.yaml +0 -0
  123. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/permissions/existing_upstream_permissions.json +0 -0
  124. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/permissions/permissions_expected_full_load.json +0 -0
  125. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/permissions/permissions_expected_incremental_load.json +0 -0
  126. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/permissions/permissions_input_full_load.json +0 -0
  127. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/permissions/permissions_input_incremental_load.json +0 -0
  128. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/existing_upstream_users.json +0 -0
  129. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/profile_response_content.json +0 -0
  130. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_expected_full_load.json +0 -0
  131. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_expected_incremental_load.json +0 -0
  132. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_input_full_load.json +0 -0
  133. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_input_full_load_modifies_protected_user.json +0 -0
  134. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_input_incremental_load.json +0 -0
  135. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_input_incremental_load_deletes_protected_user.json +0 -0
  136. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/data/provisioning/entities/users/users_input_incremental_load_modifies_protected_user.json +0 -0
  137. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/panther/__init__.py +0 -0
  138. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/panther/test_api_wrapper.py +0 -0
  139. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/panther/test_sdk_wrapper.py +0 -0
  140. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/__init__.py +0 -0
  141. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/__init__.py +0 -0
  142. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/users/__init__.py +0 -0
  143. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/users/test_permissions.py +0 -0
  144. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/users/test_user_groups.py +0 -0
  145. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/users/test_users.py +0 -0
  146. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/workspaces/__init__.py +0 -0
  147. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/workspaces/test_provisioning.py +0 -0
  148. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/workspaces/test_workspace.py +0 -0
  149. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/workspaces/test_workspace_data_filters.py +0 -0
  150. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/workspaces/test_workspace_data_parser.py +0 -0
  151. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/entities/workspaces/test_workspace_data_validator.py +0 -0
  152. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/provisioning/test_provisioning.py +0 -0
  153. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/__init__.py +0 -0
  154. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/test_input_processor.py +0 -0
  155. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/test_input_validator.py +0 -0
  156. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/test_ldm_extension_manager.py +0 -0
  157. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/test_models/__init__.py +0 -0
  158. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/test_models/test_analytical_object.py +0 -0
  159. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/test_ldm_extension/test_models/test_custom_data_object.py +0 -0
  160. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tests/utils/test_rate_limiter.py +0 -0
  161. {gooddata_pipelines-1.52.1.dev1 → gooddata_pipelines-1.52.1.dev3}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gooddata-pipelines
3
- Version: 1.52.1.dev1
3
+ Version: 1.52.1.dev3
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.52.1.dev1
11
+ Requires-Dist: gooddata-sdk~=1.52.1.dev3
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
@@ -27,9 +27,10 @@ You can use the package to manage following resources in GDC:
27
27
  - User/Group permissions
28
28
  - User Data Filters
29
29
  - Child workspaces (incl. Workspace Data Filter settings)
30
- 1. _[PLANNED]:_ Backup and restore of workspaces
31
- 1. _[PLANNED]:_ Custom fields management
32
- - extend the Logical Data Model of a child workspace
30
+ 1. Backup and restore of workspaces
31
+ - Create and backup snapshots of workspace metadata.
32
+ 1. LDM Extension
33
+ - extend the Logical Data Model of a child workspace with custom datasets and fields
33
34
 
34
35
  In case you are not interested in incorporating a library in your own program but would like to use a ready-made script, consider having a look at [GoodData Productivity Tools](https://github.com/gooddata/gooddata-productivity-tools).
35
36
 
@@ -10,9 +10,10 @@ You can use the package to manage following resources in GDC:
10
10
  - User/Group permissions
11
11
  - User Data Filters
12
12
  - Child workspaces (incl. Workspace Data Filter settings)
13
- 1. _[PLANNED]:_ Backup and restore of workspaces
14
- 1. _[PLANNED]:_ Custom fields management
15
- - extend the Logical Data Model of a child workspace
13
+ 1. Backup and restore of workspaces
14
+ - Create and backup snapshots of workspace metadata.
15
+ 1. LDM Extension
16
+ - extend the Logical Data Model of a child workspace with custom datasets and fields
16
17
 
17
18
  In case you are not interested in incorporating a library in your own program but would like to use a ready-made script, consider having a look at [GoodData Productivity Tools](https://github.com/gooddata/gooddata-productivity-tools).
18
19
 
@@ -10,6 +10,10 @@ from .backup_and_restore.models.storage import (
10
10
  S3StorageConfig,
11
11
  StorageType,
12
12
  )
13
+ from .backup_and_restore.restore_manager import (
14
+ RestoreManager,
15
+ WorkspaceToRestore,
16
+ )
13
17
  from .backup_and_restore.storage.local_storage import LocalStorage
14
18
  from .backup_and_restore.storage.s3_storage import S3Storage
15
19
 
@@ -57,6 +61,8 @@ from .provisioning.generic.provision import provision
57
61
 
58
62
  __all__ = [
59
63
  "BackupManager",
64
+ "RestoreManager",
65
+ "WorkspaceToRestore",
60
66
  "BackupRestoreConfig",
61
67
  "StorageType",
62
68
  "LocalStorage",
@@ -167,6 +167,17 @@ class ApiMethods:
167
167
  endpoint = f"/layout/workspaces/{workspace_id}/userDataFilters"
168
168
  return self._get(endpoint)
169
169
 
170
+ def put_user_data_filters(
171
+ self, workspace_id: str, user_data_filters: dict[str, Any]
172
+ ) -> requests.Response:
173
+ """Puts the user data filters into GoodData workspace."""
174
+ headers = {**self.headers, "Content-Type": "application/json"}
175
+ return self._put(
176
+ f"/layout/workspaces/{workspace_id}/userDataFilters",
177
+ user_data_filters,
178
+ headers,
179
+ )
180
+
170
181
  def get_automations(self, workspace_id: str) -> requests.Response:
171
182
  """Gets the automations for a given workspace."""
172
183
  endpoint = (
@@ -174,6 +185,22 @@ class ApiMethods:
174
185
  )
175
186
  return self._get(endpoint)
176
187
 
188
+ def post_automation(
189
+ self, workspace_id: str, automation: dict[str, Any]
190
+ ) -> requests.Response:
191
+ """Posts an automation for a given workspace."""
192
+ endpoint = f"/entities/workspaces/{workspace_id}/automations"
193
+ return self._post(endpoint, automation)
194
+
195
+ def delete_automation(
196
+ self, workspace_id: str, automation_id: str
197
+ ) -> requests.Response:
198
+ """Deletes an automation for a given workspace."""
199
+ endpoint = (
200
+ f"/entities/workspaces/{workspace_id}/automations/{automation_id}"
201
+ )
202
+ return self._delete(endpoint)
203
+
177
204
  def get_all_metrics(self, workspace_id: str) -> requests.Response:
178
205
  """Get all metrics from the specified workspace.
179
206
 
@@ -1,23 +1,20 @@
1
1
  # (C) 2025 GoodData Corporation
2
2
 
3
- import json
4
3
  import os
5
4
  import shutil
6
5
  import tempfile
7
6
  import time
8
7
  import traceback
9
8
  from pathlib import Path
10
- from typing import Any, Type
9
+ from typing import Any
11
10
 
12
11
  import attrs
13
12
  import requests
14
- import yaml
15
- from gooddata_sdk.utils import PROFILES_FILE_PATH, profile_content
16
13
 
17
- from gooddata_pipelines.api.gooddata_api_wrapper import GoodDataApi
18
14
  from gooddata_pipelines.backup_and_restore.backup_input_processor import (
19
15
  BackupInputProcessor,
20
16
  )
17
+ from gooddata_pipelines.backup_and_restore.base_manager import BaseManager
21
18
  from gooddata_pipelines.backup_and_restore.constants import (
22
19
  BackupSettings,
23
20
  DirNames,
@@ -25,18 +22,10 @@ from gooddata_pipelines.backup_and_restore.constants import (
25
22
  from gooddata_pipelines.backup_and_restore.models.input_type import InputType
26
23
  from gooddata_pipelines.backup_and_restore.models.storage import (
27
24
  BackupRestoreConfig,
28
- StorageType,
29
25
  )
30
26
  from gooddata_pipelines.backup_and_restore.storage.base_storage import (
31
27
  BackupStorage,
32
28
  )
33
- from gooddata_pipelines.backup_and_restore.storage.local_storage import (
34
- LocalStorage,
35
- )
36
- from gooddata_pipelines.backup_and_restore.storage.s3_storage import (
37
- S3Storage,
38
- )
39
- from gooddata_pipelines.logger import LogObserver
40
29
  from gooddata_pipelines.utils.rate_limiter import RateLimiter
41
30
 
42
31
 
@@ -45,16 +34,12 @@ class BackupBatch:
45
34
  list_of_ids: list[str]
46
35
 
47
36
 
48
- class BackupManager:
37
+ class BackupManager(BaseManager):
49
38
  storage: BackupStorage
50
39
 
51
40
  def __init__(self, host: str, token: str, config: BackupRestoreConfig):
52
- self._api = GoodDataApi(host, token)
53
- self.logger = LogObserver()
54
-
55
- self.config = config
41
+ super().__init__(host, token, config)
56
42
 
57
- self.storage = self._get_storage(self.config)
58
43
  self.org_id = self._api.get_organization_id()
59
44
 
60
45
  self.loader = BackupInputProcessor(self._api, self.config.api_page_size)
@@ -63,39 +48,6 @@ class BackupManager:
63
48
  calls_per_second=self.config.api_calls_per_second,
64
49
  )
65
50
 
66
- @classmethod
67
- def create(
68
- cls: Type["BackupManager"],
69
- config: BackupRestoreConfig,
70
- host: str,
71
- token: str,
72
- ) -> "BackupManager":
73
- """Creates a backup worker instance using the provided host and token."""
74
- return cls(host=host, token=token, config=config)
75
-
76
- @classmethod
77
- def create_from_profile(
78
- cls: Type["BackupManager"],
79
- config: BackupRestoreConfig,
80
- profile: str = "default",
81
- profiles_path: Path = PROFILES_FILE_PATH,
82
- ) -> "BackupManager":
83
- """Creates a backup worker instance using a GoodData profile file."""
84
- content = profile_content(profile, profiles_path)
85
- return cls(**content, config=config)
86
-
87
- @staticmethod
88
- def _get_storage(conf: BackupRestoreConfig) -> BackupStorage:
89
- """Returns the storage class based on the storage type."""
90
- if conf.storage_type == StorageType.S3:
91
- return S3Storage(conf)
92
- elif conf.storage_type == StorageType.LOCAL:
93
- return LocalStorage(conf)
94
- else:
95
- raise RuntimeError(
96
- f'Unsupported storage type "{conf.storage_type.value}".'
97
- )
98
-
99
51
  def get_user_data_filters(self, ws_id: str) -> dict:
100
52
  """Returns the user data filters for the specified workspace."""
101
53
  with self._api_rate_limiter:
@@ -133,19 +85,13 @@ class BackupManager:
133
85
  "user_data_filters",
134
86
  filter["id"] + ".yaml",
135
87
  )
136
- self._write_to_yaml(udf_file_path, filter)
88
+ self.yaml_utils.dump(udf_file_path, filter)
137
89
 
138
90
  @staticmethod
139
91
  def _move_folder(source: Path, destination: Path) -> None:
140
92
  """Moves the source folder to the destination."""
141
93
  shutil.move(source, destination)
142
94
 
143
- @staticmethod
144
- def _write_to_yaml(path: str, source: Any) -> None:
145
- """Writes the source to a YAML file."""
146
- with open(path, "w") as outfile:
147
- yaml.dump(source, outfile)
148
-
149
95
  def _get_automations_from_api(self, workspace_id: str) -> Any:
150
96
  """Returns automations for the workspace as JSON."""
151
97
  with self._api_rate_limiter:
@@ -182,8 +128,7 @@ class BackupManager:
182
128
 
183
129
  # Store the automations in a JSON file
184
130
  if len(automations["data"]) > 0:
185
- with open(automations_file_path, "w") as f:
186
- json.dump(automations, f)
131
+ self.json_utils.dump(automations_file_path, automations)
187
132
 
188
133
  def store_declarative_filter_views(
189
134
  self, export_path: Path, workspace_id: str
@@ -0,0 +1,73 @@
1
+ # (C) 2025 GoodData Corporation
2
+
3
+ import abc
4
+ from pathlib import Path
5
+ from typing import Type, TypeVar
6
+
7
+ from gooddata_sdk.utils import PROFILES_FILE_PATH, profile_content
8
+
9
+ from gooddata_pipelines.api.gooddata_api_wrapper import GoodDataApi
10
+ from gooddata_pipelines.backup_and_restore.models.storage import (
11
+ BackupRestoreConfig,
12
+ StorageType,
13
+ )
14
+ from gooddata_pipelines.backup_and_restore.storage.base_storage import (
15
+ BackupStorage,
16
+ )
17
+ from gooddata_pipelines.backup_and_restore.storage.local_storage import (
18
+ LocalStorage,
19
+ )
20
+ from gooddata_pipelines.backup_and_restore.storage.s3_storage import S3Storage
21
+ from gooddata_pipelines.logger import LogObserver
22
+ from gooddata_pipelines.utils.file_utils import JsonUtils, YamlUtils
23
+
24
+ ManagerT = TypeVar("ManagerT", bound="BaseManager")
25
+
26
+
27
+ class BaseManager(abc.ABC):
28
+ """Base class to provide constructors for backup and restore managers."""
29
+
30
+ storage: BackupStorage
31
+
32
+ def __init__(self, host: str, token: str, config: BackupRestoreConfig):
33
+ self.config = config
34
+
35
+ self._api: GoodDataApi = GoodDataApi(host, token)
36
+ self.logger: LogObserver = LogObserver()
37
+
38
+ self.storage = self._get_storage(self.config)
39
+
40
+ self.yaml_utils = YamlUtils()
41
+ self.json_utils = JsonUtils()
42
+
43
+ def _get_storage(self, conf: BackupRestoreConfig) -> BackupStorage:
44
+ """Returns the storage class based on the storage type."""
45
+ if conf.storage_type == StorageType.S3:
46
+ return S3Storage(conf)
47
+ elif conf.storage_type == StorageType.LOCAL:
48
+ return LocalStorage(conf)
49
+ else:
50
+ raise RuntimeError(
51
+ f'Unsupported storage type "{conf.storage_type.value}".'
52
+ )
53
+
54
+ @classmethod
55
+ def create(
56
+ cls: Type[ManagerT],
57
+ config: BackupRestoreConfig,
58
+ host: str,
59
+ token: str,
60
+ ) -> ManagerT:
61
+ """Creates a backup worker instance using the provided host and token."""
62
+ return cls(host=host, token=token, config=config)
63
+
64
+ @classmethod
65
+ def create_from_profile(
66
+ cls: Type[ManagerT],
67
+ config: BackupRestoreConfig,
68
+ profile: str = "default",
69
+ profiles_path: Path = PROFILES_FILE_PATH,
70
+ ) -> ManagerT:
71
+ """Creates a backup worker instance using a GoodData profile file."""
72
+ content = profile_content(profile, profiles_path)
73
+ return cls(host=content["host"], token=content["token"], config=config)
@@ -23,13 +23,14 @@ class DirNames:
23
23
 
24
24
  @attrs.frozen
25
25
  class ApiDefaults:
26
- DEFAULT_PAGE_SIZE = 100
27
- DEFAULT_BATCH_SIZE = 100
28
- DEFAULT_API_CALLS_PER_SECOND = 1.0
26
+ PAGE_SIZE = 100
27
+ BATCH_SIZE = 100
28
+ CALLS_PER_SECOND = 1.0
29
29
 
30
30
 
31
31
  @attrs.frozen
32
- class BackupSettings(ApiDefaults):
32
+ class BackupSettings:
33
+ API = ApiDefaults()
33
34
  MAX_RETRIES = 3
34
35
  RETRY_DELAY = 5 # seconds
35
36
  TIMESTAMP_SDK_FOLDER = (
@@ -0,0 +1,156 @@
1
+ # (C) 2025 GoodData Corporation
2
+
3
+ from enum import Enum
4
+ from typing import Annotated
5
+
6
+ import yaml
7
+ from pydantic import BaseModel, Field, model_validator
8
+
9
+ from gooddata_pipelines.backup_and_restore.constants import BackupSettings
10
+
11
+
12
+ class StorageType(Enum):
13
+ """Type of storage."""
14
+
15
+ S3 = "s3"
16
+ LOCAL = "local"
17
+
18
+
19
+ class S3StorageConfig(BaseModel):
20
+ """Configuration for S3 storage.
21
+
22
+ Can be created using the following constructor methods:
23
+ - `from_iam_role`
24
+ - `from_aws_credentials`
25
+ - `from_aws_profile`
26
+ """
27
+
28
+ backup_path: str
29
+ bucket: str
30
+ profile: str | None = None
31
+ aws_access_key_id: str | None = None
32
+ aws_secret_access_key: str | None = None
33
+ aws_default_region: str = "us-east-1"
34
+
35
+ @classmethod
36
+ def from_iam_role(cls, backup_path: str, bucket: str) -> "S3StorageConfig":
37
+ """Use default IAM role or environment credentials.
38
+
39
+ Args:
40
+ backup_path: The path to the backup directory.
41
+ bucket: The name of the S3 bucket.
42
+
43
+ Returns:
44
+ S3StorageConfig: The S3 storage configuration.
45
+ """
46
+ return cls(backup_path=backup_path, bucket=bucket)
47
+
48
+ @classmethod
49
+ def from_aws_credentials(
50
+ cls,
51
+ backup_path: str,
52
+ bucket: str,
53
+ aws_access_key_id: str,
54
+ aws_secret_access_key: str,
55
+ aws_default_region: str,
56
+ ) -> "S3StorageConfig":
57
+ """Use explicit AWS access keys and region.
58
+
59
+ Args:
60
+ backup_path: The path to the backup directory.
61
+ bucket: The name of the S3 bucket.
62
+ aws_access_key_id: The AWS access key ID.
63
+ aws_secret_access_key: The AWS secret access key.
64
+ aws_default_region: The AWS default region.
65
+
66
+ Returns:
67
+ S3StorageConfig: The S3 storage configuration.
68
+ """
69
+ return cls(
70
+ backup_path=backup_path,
71
+ bucket=bucket,
72
+ aws_access_key_id=aws_access_key_id,
73
+ aws_secret_access_key=aws_secret_access_key,
74
+ aws_default_region=aws_default_region,
75
+ )
76
+
77
+ @classmethod
78
+ def from_aws_profile(
79
+ cls, backup_path: str, bucket: str, profile: str
80
+ ) -> "S3StorageConfig":
81
+ """Use a named AWS CLI profile.
82
+
83
+ Args:
84
+ backup_path: The path to the backup directory.
85
+ bucket: The name of the S3 bucket.
86
+ profile: The name of the AWS profile.
87
+
88
+ Returns:
89
+ S3StorageConfig: The S3 storage configuration.
90
+ """
91
+ return cls(backup_path=backup_path, bucket=bucket, profile=profile)
92
+
93
+
94
+ class LocalStorageConfig(BaseModel):
95
+ """Placeholder for local storage config."""
96
+
97
+ backup_path: str = Field(default="local_backups")
98
+
99
+
100
+ class BackupRestoreConfig(BaseModel):
101
+ """Configuration for backup and restore.
102
+
103
+ Args:
104
+ storage_type: The type of storage to use. Defaults to `StorageType.LOCAL`.
105
+ storage: Storage configuration. Either `S3StorageConfig` or `LocalStorageConfig`. Defaults to `LocalStorageConfig()`.
106
+ api_page_size: The page size for fetching workspace relationships. Defaults to `BackupSettings.API.PAGE_SIZE`.
107
+ batch_size: The batch size for fetching workspace relationships. Defaults to `BackupSettings.API.BATCH_SIZE`.
108
+ api_calls_per_second: The maximum API calls per second (rate limiting). Defaults to `BackupSettings.API.CALLS_PER_SECOND`.
109
+ """
110
+
111
+ storage_type: StorageType = Field(default=StorageType.LOCAL)
112
+ storage: S3StorageConfig | LocalStorageConfig = Field(
113
+ default_factory=LocalStorageConfig
114
+ )
115
+ api_page_size: Annotated[
116
+ int,
117
+ Field(
118
+ gt=0,
119
+ description="Page size must be greater than 0",
120
+ ),
121
+ ] = Field(default=BackupSettings.API.PAGE_SIZE)
122
+ batch_size: Annotated[
123
+ int,
124
+ Field(
125
+ gt=0,
126
+ description="Batch size must be greater than 0",
127
+ ),
128
+ ] = Field(default=BackupSettings.API.BATCH_SIZE)
129
+ api_calls_per_second: Annotated[
130
+ float,
131
+ Field(
132
+ gt=0,
133
+ description="Maximum API calls per second (rate limiting)",
134
+ ),
135
+ ] = Field(default=BackupSettings.API.CALLS_PER_SECOND)
136
+
137
+ @classmethod
138
+ def from_yaml(cls, conf_path: str) -> "BackupRestoreConfig":
139
+ with open(conf_path, "r") as stream:
140
+ conf: dict = yaml.safe_load(stream)
141
+ return cls(**conf)
142
+
143
+ @model_validator(mode="after")
144
+ def validate_storage(self) -> "BackupRestoreConfig":
145
+ """Check that the storage gets correct configuration when using S3 storage"""
146
+ if self.storage_type == StorageType.S3:
147
+ if not isinstance(self.storage, S3StorageConfig):
148
+ raise ValueError(
149
+ "S3 storage must be configured with S3StorageConfig object"
150
+ )
151
+ elif self.storage_type == StorageType.LOCAL:
152
+ if not isinstance(self.storage, LocalStorageConfig):
153
+ raise ValueError(
154
+ "Local storage must be configured with LocalStorageConfig object"
155
+ )
156
+ return self