castor-extractor 0.9.2__tar.gz → 0.10.1__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 castor-extractor might be problematic. Click here for more details.

Files changed (297) hide show
  1. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/CHANGELOG.md +8 -0
  2. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/PKG-INFO +1 -1
  3. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/client/client.py +4 -1
  4. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/client/pagination.py +8 -3
  5. castor_extractor-0.10.1/castor_extractor/visualization/domo/client/pagination_test.py +22 -0
  6. castor_extractor-0.10.1/castor_extractor/visualization/looker/__init__.py +3 -0
  7. castor_extractor-0.10.1/castor_extractor/visualization/looker/api/__init__.py +3 -0
  8. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/api/client.py +5 -6
  9. castor_extractor-0.10.1/castor_extractor/visualization/looker/api/utils.py +24 -0
  10. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/extract.py +13 -12
  11. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/multithreading.py +5 -17
  12. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/client.py +47 -15
  13. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/client_test.py +4 -1
  14. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/pyproject.toml +1 -1
  15. castor_extractor-0.9.2/castor_extractor/visualization/looker/__init__.py +0 -9
  16. castor_extractor-0.9.2/castor_extractor/visualization/looker/api/__init__.py +0 -7
  17. castor_extractor-0.9.2/castor_extractor/visualization/looker/api/utils.py +0 -49
  18. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/Dockerfile +0 -0
  19. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/LICENCE +0 -0
  20. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/README.md +0 -0
  21. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/__init__.py +0 -0
  22. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/__init__.py +0 -0
  23. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_bigquery.py +0 -0
  24. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_domo.py +0 -0
  25. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_looker.py +0 -0
  26. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_metabase_api.py +0 -0
  27. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_metabase_db.py +0 -0
  28. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_mode.py +0 -0
  29. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_postgres.py +0 -0
  30. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_powerbi.py +0 -0
  31. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_qlik.py +0 -0
  32. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_redshift.py +0 -0
  33. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_sigma.py +0 -0
  34. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_snowflake.py +0 -0
  35. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/extract_tableau.py +0 -0
  36. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/file_check.py +0 -0
  37. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/commands/upload.py +0 -0
  38. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/__init__.py +0 -0
  39. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/column.py +0 -0
  40. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/column_test.py +0 -0
  41. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/constants.py +0 -0
  42. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/enums.py +0 -0
  43. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/file.py +0 -0
  44. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/file_test.py +0 -0
  45. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/file_test_users.csv +0 -0
  46. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
  47. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/templates/__init__.py +0 -0
  48. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
  49. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/logger.py +0 -0
  50. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/__init__.py +0 -0
  51. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/dbt/__init__.py +0 -0
  52. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/dbt/assets.py +0 -0
  53. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/dbt/client/__init__.py +0 -0
  54. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/dbt/client/client.py +0 -0
  55. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/dbt/client/client_test.py +0 -0
  56. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/transformation/dbt/client/credentials.py +0 -0
  57. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/types.py +0 -0
  58. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/__init__.py +0 -0
  59. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/constant.py +0 -0
  60. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/env.py +0 -0
  61. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/env_test.py +0 -0
  62. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/upload.py +0 -0
  63. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/upload_test.py +0 -0
  64. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/uploader/utils.py +0 -0
  65. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/__init__.py +0 -0
  66. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/collection.py +0 -0
  67. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/constants.py +0 -0
  68. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/deprecate.py +0 -0
  69. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/env.py +0 -0
  70. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/files.py +0 -0
  71. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/files_test.py +0 -0
  72. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/formatter.py +0 -0
  73. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/formatter_test.csv +0 -0
  74. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/formatter_test.json +0 -0
  75. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/formatter_test.py +0 -0
  76. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/json_stream_write.py +0 -0
  77. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/load.py +0 -0
  78. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/object.py +0 -0
  79. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/object_test.py +0 -0
  80. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/pager.py +0 -0
  81. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/pager_test.py +0 -0
  82. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/retry.py +0 -0
  83. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/retry_test.py +0 -0
  84. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/safe.py +0 -0
  85. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/safe_test.py +0 -0
  86. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/store.py +0 -0
  87. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/string.py +0 -0
  88. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/string_test.py +0 -0
  89. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/time.py +0 -0
  90. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/time_test.py +0 -0
  91. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/type.py +0 -0
  92. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/uri.py +0 -0
  93. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/uri_test.py +0 -0
  94. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/validation.py +0 -0
  95. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/validation_test.py +0 -0
  96. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/utils/write.py +0 -0
  97. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/__init__.py +0 -0
  98. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/__init__.py +0 -0
  99. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/assets.py +0 -0
  100. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/client/__init__.py +0 -0
  101. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/client/client_test.py +0 -0
  102. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/client/credentials.py +0 -0
  103. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
  104. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/constants.py +0 -0
  105. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/domo/extract.py +0 -0
  106. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/api/client_test.py +0 -0
  107. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/api/constants.py +0 -0
  108. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/api/sdk.py +0 -0
  109. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
  110. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/assets.py +0 -0
  111. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/constant.py +0 -0
  112. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/env.py +0 -0
  113. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/fields.py +0 -0
  114. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/fields_test.py +0 -0
  115. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/looker/parameters.py +0 -0
  116. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/__init__.py +0 -0
  117. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/assets.py +0 -0
  118. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
  119. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
  120. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
  121. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
  122. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
  123. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
  124. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
  125. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
  126. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
  127. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
  128. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
  129. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
  130. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
  131. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
  132. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
  133. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
  134. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
  135. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
  136. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/client/shared.py +0 -0
  137. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/errors.py +0 -0
  138. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/extract.py +0 -0
  139. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/metabase/types.py +0 -0
  140. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/__init__.py +0 -0
  141. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/assets.py +0 -0
  142. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/client/__init__.py +0 -0
  143. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/client/client.py +0 -0
  144. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/client/client_test.json +0 -0
  145. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/client/client_test.py +0 -0
  146. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/client/constants.py +0 -0
  147. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/client/credentials.py +0 -0
  148. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/errors.py +0 -0
  149. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/mode/extract.py +0 -0
  150. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/__init__.py +0 -0
  151. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/assets.py +0 -0
  152. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
  153. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
  154. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
  155. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
  156. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/rest.py +0 -0
  157. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/rest_test.py +0 -0
  158. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/utils.py +0 -0
  159. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/client/utils_test.py +0 -0
  160. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/powerbi/extract.py +0 -0
  161. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/__init__.py +0 -0
  162. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/assets.py +0 -0
  163. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
  164. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/constants.py +0 -0
  165. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
  166. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
  167. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
  168. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
  169. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
  170. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
  171. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
  172. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
  173. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/master.py +0 -0
  174. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/rest.py +0 -0
  175. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
  176. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/constants.py +0 -0
  177. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/qlik/extract.py +0 -0
  178. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/__init__.py +0 -0
  179. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/assets.py +0 -0
  180. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
  181. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/client/client.py +0 -0
  182. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/client/client_test.py +0 -0
  183. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
  184. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
  185. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
  186. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/constants.py +0 -0
  187. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/sigma/extract.py +0 -0
  188. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/__init__.py +0 -0
  189. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/assets.py +0 -0
  190. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/client/__init__.py +0 -0
  191. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/client/client.py +0 -0
  192. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/client/client_utils.py +0 -0
  193. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/client/credentials.py +0 -0
  194. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/client/project.py +0 -0
  195. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/client/safe_mode.py +0 -0
  196. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/constants.py +0 -0
  197. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/errors.py +0 -0
  198. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/extract.py +0 -0
  199. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/gql_fields.py +0 -0
  200. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/__init__.py +0 -0
  201. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/__init__.py +0 -0
  202. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_1_get.json +0 -0
  203. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_2_get.json +0 -0
  204. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/auth.xml +0 -0
  205. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/project_get.xml +0 -0
  206. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/user_get.xml +0 -0
  207. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/view_get_usage.xml +0 -0
  208. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/workbook_get.xml +0 -0
  209. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/graphql/__init__.py +0 -0
  210. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/graphql/paginated_object_test.py +0 -0
  211. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/__init__.py +0 -0
  212. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/auth_test.py +0 -0
  213. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/credentials_test.py +0 -0
  214. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/projects_test.py +0 -0
  215. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/usages_test.py +0 -0
  216. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/users_test.py +0 -0
  217. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/rest_api/workbooks_test.py +0 -0
  218. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/utils/__init__.py +0 -0
  219. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tests/unit/utils/env_key.py +0 -0
  220. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/tsc_fields.py +0 -0
  221. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/types.py +0 -0
  222. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/visualization/tableau/usage.py +0 -0
  223. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/__init__.py +0 -0
  224. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/__init__.py +0 -0
  225. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/asset.py +0 -0
  226. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/client.py +0 -0
  227. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/extract.py +0 -0
  228. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/query.py +0 -0
  229. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
  230. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
  231. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
  232. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/extract.py +0 -0
  233. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
  234. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
  235. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
  236. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
  237. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
  238. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
  239. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
  240. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
  241. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
  242. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
  243. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/query.py +0 -0
  244. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/bigquery/types.py +0 -0
  245. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/__init__.py +0 -0
  246. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/client.py +0 -0
  247. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/extract.py +0 -0
  248. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
  249. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
  250. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
  251. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
  252. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
  253. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
  254. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
  255. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/postgres/query.py +0 -0
  256. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/__init__.py +0 -0
  257. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/client.py +0 -0
  258. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/client_test.py +0 -0
  259. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/extract.py +0 -0
  260. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
  261. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
  262. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
  263. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
  264. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
  265. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
  266. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
  267. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
  268. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
  269. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -0
  270. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/redshift/query.py +0 -0
  271. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
  272. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/client.py +0 -0
  273. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
  274. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/extract.py +0 -0
  275. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
  276. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/column.sql +0 -0
  277. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
  278. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
  279. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
  280. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
  281. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/query.sql +0 -0
  282. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
  283. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/schema.sql +0 -0
  284. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/table.sql +0 -0
  285. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
  286. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
  287. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/snowflake/query.py +0 -0
  288. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/__init__.py +0 -0
  289. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/extract.py +0 -0
  290. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/.sqlfluff +0 -0
  291. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/column.sql +0 -0
  292. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/database.sql +0 -0
  293. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/query.sql +0 -0
  294. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/schema.sql +0 -0
  295. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/table.sql +0 -0
  296. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/user.sql +0 -0
  297. {castor_extractor-0.9.2 → castor_extractor-0.10.1}/castor_extractor/warehouse/synapse/queries/view_ddl.sql +0 -0
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.1 - 2023-12-04
4
+
5
+ * Domo: fix pagination
6
+
7
+ ## 0.10.0 - 2023-11-28
8
+
9
+ * Looker : extract all Looker Explores, even if unused in Dashboards
10
+
3
11
  ## 0.9.2 - 2023-11-23
4
12
 
5
13
  * Looker : remove deprecated all_looks parameter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.9.2
3
+ Version: 0.10.1
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -128,7 +128,10 @@ class DomoClient:
128
128
  while pagination.needs_increment:
129
129
  results = self._get_many(
130
130
  endpoint=endpoint,
131
- params={"offset": pagination.offset},
131
+ params={
132
+ "offset": pagination.offset,
133
+ "limit": pagination.per_page,
134
+ },
132
135
  )
133
136
  all_results.extend(results)
134
137
  number_of_items = len(results)
@@ -1,23 +1,28 @@
1
1
  from dataclasses import dataclass
2
+ from typing import Optional
2
3
 
3
- PER_PAGE = 50
4
+ PER_PAGE = 50 # maximum value accepted by DOMO is 50
4
5
 
5
6
 
6
7
  @dataclass
7
8
  class Pagination:
8
9
  """Handles pagination within DOMO Api"""
9
10
 
10
- number_results: int = PER_PAGE # max init
11
+ number_results: Optional[int] = None
11
12
  offset: int = 0
12
13
  per_page: int = PER_PAGE
13
14
  should_stop: bool = False
14
15
 
15
16
  @property
16
17
  def needs_increment(self) -> bool:
18
+ if self.number_results is None:
19
+ return True # first iteration
20
+
17
21
  if (self.number_results < self.per_page) or self.should_stop:
18
22
  return False
23
+
19
24
  return True
20
25
 
21
26
  def increment_offset(self, number_results: int) -> None:
22
- self.offset += self.per_page
27
+ self.offset += number_results
23
28
  self.number_results = number_results
@@ -0,0 +1,22 @@
1
+ from .pagination import Pagination
2
+
3
+
4
+ def test_pagination():
5
+ per_page = 20
6
+
7
+ pagination = Pagination(per_page=per_page)
8
+
9
+ assert pagination.number_results is None
10
+ assert pagination.offset == 0
11
+
12
+ pagination.increment_offset(per_page)
13
+ assert pagination.offset == per_page
14
+ assert pagination.needs_increment
15
+
16
+ pagination.increment_offset(per_page)
17
+ assert pagination.offset == per_page * 2
18
+ assert pagination.needs_increment
19
+
20
+ pagination.increment_offset(5)
21
+ assert pagination.offset == per_page * 2 + 5
22
+ assert not pagination.needs_increment
@@ -0,0 +1,3 @@
1
+ from .api import ApiClient, Credentials, lookml_explore_names
2
+ from .assets import LookerAsset
3
+ from .extract import extract_all, iterate_all_data
@@ -0,0 +1,3 @@
1
+ from .client import ApiClient
2
+ from .sdk import Credentials
3
+ from .utils import lookml_explore_names
@@ -191,7 +191,7 @@ class ApiClient:
191
191
  def explores(
192
192
  self,
193
193
  explore_names=Iterator[Tuple[str, str]],
194
- ) -> List[LookmlModelExplore]:
194
+ ) -> Iterator[LookmlModelExplore]:
195
195
  """Iterates explores of the given Looker account for the provided model/explore names"""
196
196
 
197
197
  @safe_mode(self._safe_mode)
@@ -202,11 +202,10 @@ class ApiClient:
202
202
  self._on_api_call()
203
203
  return explore
204
204
 
205
- explores = [
206
- _call(model_name, explore_name)
207
- for model_name, explore_name in explore_names
208
- ]
209
- return list(filter(None, explores))
205
+ for lookml_model_name, lookml_explore_name_ in explore_names:
206
+ explore_ = _call(lookml_model_name, lookml_explore_name_)
207
+ if explore_ is not None:
208
+ yield explore_
210
209
 
211
210
  def connections(self) -> List[DBConnection]:
212
211
  """Lists databases connections of the given Looker account"""
@@ -0,0 +1,24 @@
1
+ from typing import Iterable, Set, Tuple
2
+
3
+ from .sdk import LookmlModel
4
+
5
+
6
+ def lookml_explore_names(
7
+ lookmls: Iterable[LookmlModel],
8
+ ) -> Set[Tuple[str, str]]:
9
+ """
10
+ Explores from the lookml models
11
+ Only valid explores are yielded: with all infos
12
+ """
13
+ model_explores = (
14
+ (model, explore)
15
+ for model in lookmls
16
+ for explore in model.explores or []
17
+ )
18
+
19
+ return {
20
+ (model.name, explore.name)
21
+ for model, explore in model_explores
22
+ # accept hidden resources
23
+ if model.name and explore.name
24
+ }
@@ -11,12 +11,8 @@ from ...utils import (
11
11
  write_json,
12
12
  write_summary,
13
13
  )
14
- from .api import (
15
- ApiClient,
16
- Credentials,
17
- dashboard_explore_names,
18
- explore_names_associated_to_dashboards,
19
- )
14
+ from .api import ApiClient, Credentials, lookml_explore_names
15
+ from .api.sdk import LookmlModel
20
16
  from .assets import LookerAsset
21
17
  from .multithreading import MultithreadingFetcher
22
18
  from .parameters import get_parameters
@@ -24,6 +20,15 @@ from .parameters import get_parameters
24
20
  logger = logging.getLogger(__name__)
25
21
 
26
22
 
23
+ def _extract_explores_by_name(
24
+ lookmls: Iterable[LookmlModel], client: ApiClient
25
+ ) -> Iterable[dict]:
26
+ explore_names = lookml_explore_names(lookmls)
27
+ explores = client.explores(explore_names)
28
+ for explore in explores:
29
+ yield deep_serialize(explore) # type: ignore
30
+
31
+
27
32
  def _safe_mode(directory: str) -> SafeMode:
28
33
  add_logging_file_handler(directory)
29
34
  return SafeMode((Exception,), float("inf"))
@@ -79,10 +84,8 @@ def iterate_all_data(
79
84
  if search_per_folder:
80
85
  dashboards_stream = fetcher.fetch_assets(LookerAsset.DASHBOARDS)
81
86
  yield LookerAsset.DASHBOARDS, StreamableList(dashboards_stream)
82
- dashboard_explore_names_ = fetcher.explores
83
87
  else:
84
88
  dashboards = client.dashboards()
85
- dashboard_explore_names_ = dashboard_explore_names(dashboards)
86
89
  yield LookerAsset.DASHBOARDS, deep_serialize(dashboards)
87
90
 
88
91
  logger.info("Extracting lookml models from Looker API")
@@ -90,10 +93,8 @@ def iterate_all_data(
90
93
  yield LookerAsset.LOOKML_MODELS, deep_serialize(lookmls)
91
94
 
92
95
  logger.info("Extracting explores from Looker API")
93
- explore_names = explore_names_associated_to_dashboards(
94
- lookmls, dashboard_explore_names_
95
- )
96
- yield LookerAsset.EXPLORES, deep_serialize(client.explores(explore_names))
96
+ explores = _extract_explores_by_name(lookmls, client)
97
+ yield LookerAsset.EXPLORES, StreamableList(explores)
97
98
  del lookmls
98
99
 
99
100
  logger.info("Extracting connections from Looker API")
@@ -2,13 +2,13 @@ import logging
2
2
  import sys
3
3
  from concurrent.futures import ThreadPoolExecutor
4
4
  from functools import partial
5
- from typing import Iterable, List, Set, Tuple
5
+ from typing import Iterable, List, Set
6
6
 
7
7
  from tqdm import tqdm # type: ignore
8
8
 
9
9
  from ...utils import RetryStrategy, deep_serialize, retry
10
- from . import ApiClient, dashboard_explore_names
11
- from .api.sdk import Dashboard, SDKError
10
+ from . import ApiClient
11
+ from .api.sdk import SDKError
12
12
  from .assets import LookerAsset
13
13
 
14
14
  logger = logging.getLogger(__name__)
@@ -54,16 +54,6 @@ class MultithreadingFetcher:
54
54
  self._thread_pool_size = thread_pool_size
55
55
  self._log_to_stdout = log_to_stdout
56
56
 
57
- self.explores: Set[Tuple[str, str]] = set()
58
-
59
- def _save_explore_names(self, dashboards_per_folder: Iterable[Dashboard]):
60
- """
61
- Since dashboards are streamed right to the file, we need to keep
62
- the relevant information to extract Explores later.
63
- """
64
- explores = dashboard_explore_names(dashboards_per_folder)
65
- self.explores.update(explores)
66
-
67
57
  def _progress_bar(self, fetch_results: Iterable, total: int) -> tqdm:
68
58
  """Create a tqdm progress bar with the appropriate logs destination"""
69
59
  file = sys.stderr
@@ -73,7 +63,7 @@ class MultithreadingFetcher:
73
63
 
74
64
  return tqdm(fetch_results, total=total, file=file)
75
65
 
76
- def fetch_assets(self, asset: LookerAsset):
66
+ def fetch_assets(self, asset: LookerAsset) -> Iterable[dict]:
77
67
  """
78
68
  Yields serialized Looks or Dashboards with a request per folder ID.
79
69
  Requests are parallelised.
@@ -88,12 +78,10 @@ class MultithreadingFetcher:
88
78
  fetch_results = executor.map(_fetch, self._folder_ids)
89
79
 
90
80
  for results in self._progress_bar(fetch_results, total_folders):
91
- if asset == LookerAsset.DASHBOARDS:
92
- self._save_explore_names(results)
93
-
94
81
  for result in results:
95
82
  if not result:
96
83
  continue
84
+
97
85
  total_assets_count += len(result)
98
86
  yield deep_serialize(result)
99
87
 
@@ -1,8 +1,12 @@
1
1
  from typing import List, Optional, Set, Tuple
2
2
 
3
+ from google.api_core.exceptions import Forbidden
4
+ from google.api_core.page_iterator import Iterator as PageIterator
3
5
  from google.cloud.bigquery import Client as GoogleCloudClient # type: ignore
6
+ from google.cloud.bigquery.dataset import Dataset # type: ignore
4
7
  from google.oauth2.service_account import Credentials # type: ignore
5
8
 
9
+ from ...utils import retry
6
10
  from ..abstract import SqlalchemyClient
7
11
 
8
12
  BIGQUERY_URI = "bigquery://"
@@ -10,6 +14,9 @@ BIGQUERY_URI = "bigquery://"
10
14
  CREDENTIALS_INFO_KEY = "credentials_info"
11
15
  PROJECT_ID_KEY = "project_id"
12
16
 
17
+ _RETRY_NUMBER = 1
18
+ _RETRY_BASE_MS = 60_000
19
+
13
20
 
14
21
  class BigQueryClient(SqlalchemyClient):
15
22
  """Connect to BigQuery and run SQL queries"""
@@ -25,6 +32,9 @@ class BigQueryClient(SqlalchemyClient):
25
32
  self._db_allowed = db_allowed
26
33
  self._db_blocked = db_blocked
27
34
  self._dataset_blocked = dataset_blocked
35
+ self.client = self._client()
36
+ self._projects: List[str] | None = None
37
+ self._datasets: List[Dataset] | None = None
28
38
 
29
39
  @staticmethod
30
40
  def name() -> str:
@@ -51,7 +61,7 @@ class BigQueryClient(SqlalchemyClient):
51
61
  def _build_uri(self, credentials: dict) -> str:
52
62
  return BIGQUERY_URI
53
63
 
54
- def _google_cloud_client(self) -> GoogleCloudClient:
64
+ def _client(self) -> GoogleCloudClient:
55
65
  assert (
56
66
  CREDENTIALS_INFO_KEY in self._options
57
67
  ), "Missing BigQuery credentials in engine's options"
@@ -61,25 +71,47 @@ class BigQueryClient(SqlalchemyClient):
61
71
  credentials=Credentials.from_service_account_info(credentials),
62
72
  )
63
73
 
64
- def _list_datasets(self) -> List:
65
- client = self._google_cloud_client()
66
- return [
67
- dataset
68
- for project_id in self.get_projects()
69
- for dataset in client.list_datasets(project_id)
70
- if self._keep_dataset(dataset.dataset_id)
71
- ]
74
+ def _list_datasets(self) -> List[Dataset]:
75
+ """
76
+ Returns datasets available for the given GCP client
77
+ Cache the result in self._datasets to reduce number of API calls
78
+ """
79
+ if self._datasets is None:
80
+ self._datasets = [
81
+ dataset
82
+ for project_id in self.get_projects()
83
+ for dataset in self.client.list_datasets(project_id)
84
+ if self._keep_dataset(dataset.dataset_id)
85
+ ]
86
+ return self._datasets
87
+
88
+ @retry((Forbidden,), count=_RETRY_NUMBER, base_ms=_RETRY_BASE_MS)
89
+ def _list_projects(self) -> PageIterator:
90
+ """
91
+ Note: Calling list_projects from GoogleCloudClient causes some
92
+ ```
93
+ google.api_core.exceptions.Forbidden: 403 GET https://bigquery.googleapis.com/bigquery/v2/projects?prettyPrint=false
94
+ Quota exceeded: Your user exceeded quota for concurrent project.lists requests.
95
+ ````
96
+
97
+ This function aims to isolate the call with a custom retry strategy.
98
+ Note that google allows a retry parameter on client.list_projects but
99
+ that looks way too complex to customize.
100
+ """
101
+ return self.client.list_projects()
72
102
 
73
103
  def get_projects(self) -> List[str]:
74
104
  """
75
105
  Returns distinct project_id available for the given GCP client
106
+ Cache the result in self._projects to reduce number of API calls
76
107
  """
77
- client = self._google_cloud_client()
78
- return [
79
- p.project_id
80
- for p in client.list_projects()
81
- if self._keep_project(p.project_id)
82
- ]
108
+ if self._projects is None:
109
+ self._projects = [
110
+ p.project_id
111
+ for p in self._list_projects()
112
+ if self._keep_project(p.project_id)
113
+ ]
114
+ return self._projects
83
115
 
84
116
  def get_regions(self) -> Set[Tuple[str, str]]:
85
117
  """
@@ -26,8 +26,11 @@ class MockBigQueryClient(BigQueryClient):
26
26
  self._db_allowed = ["project_2", "project_1"]
27
27
  self._dataset_blocked = ["hidden_dataset"]
28
28
  self._db_blocked = ["hidden_project"]
29
+ self._projects = None
30
+ self._datasets = None
31
+ self.client = self._client()
29
32
 
30
- def _google_cloud_client(self) -> Mock:
33
+ def _client(self) -> Mock:
31
34
  fake_client = Mock()
32
35
  fake_client.list_projects = Mock(
33
36
  return_value=[
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.2"]
3
3
 
4
4
  [tool.poetry]
5
5
  name = "castor-extractor"
6
- version = "0.9.2"
6
+ version = "0.10.1"
7
7
  description = "Extract your metadata assets."
8
8
  authors = ["Castor <support@castordoc.com>"]
9
9
  license = "EULA"
@@ -1,9 +0,0 @@
1
- from .api import (
2
- ApiClient,
3
- Credentials,
4
- dashboard_explore_names,
5
- explore_names_associated_to_dashboards,
6
- lookml_explore_names,
7
- )
8
- from .assets import LookerAsset
9
- from .extract import extract_all, iterate_all_data
@@ -1,7 +0,0 @@
1
- from .client import ApiClient
2
- from .sdk import Credentials
3
- from .utils import (
4
- dashboard_explore_names,
5
- explore_names_associated_to_dashboards,
6
- lookml_explore_names,
7
- )
@@ -1,49 +0,0 @@
1
- from typing import Iterable, Set, Tuple
2
-
3
- from .sdk import Dashboard, LookmlModel
4
-
5
-
6
- def lookml_explore_names(
7
- lookmls: Iterable[LookmlModel],
8
- ) -> Set[Tuple[str, str]]:
9
- """
10
- Explores from the lookml models
11
- Only valid explores are yielded: with all infos
12
- """
13
- model_explores = (
14
- (model, explore)
15
- for model in lookmls
16
- for explore in model.explores or []
17
- )
18
-
19
- return {
20
- (model.name, explore.name)
21
- for model, explore in model_explores
22
- # accept hidden resources
23
- if model.name and explore.name
24
- }
25
-
26
-
27
- def dashboard_explore_names(
28
- dashboards: Iterable[Dashboard],
29
- ) -> Set[Tuple[str, str]]:
30
- """Explores that appear in dashboards"""
31
- elements = (
32
- element
33
- for dashboard in dashboards
34
- for element in dashboard.dashboard_elements or []
35
- )
36
-
37
- return {
38
- (element.query.model, element.query.view)
39
- for element in elements
40
- if element.query and element.query.model and element.query.view
41
- }
42
-
43
-
44
- def explore_names_associated_to_dashboards(
45
- lookmls: Iterable[LookmlModel],
46
- dashboard_explore_names_: Set[Tuple[str, str]],
47
- ):
48
- """Retrieve only explores that are associated to a looker dashboard"""
49
- return lookml_explore_names(lookmls).intersection(dashboard_explore_names_)