castor-extractor 0.16.9__tar.gz → 0.16.15__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 (377) hide show
  1. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/CHANGELOG.md +24 -0
  2. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/PKG-INFO +1 -1
  3. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/api.py +8 -3
  4. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/retry.py +3 -1
  5. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/client/client.py +8 -2
  6. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/client/gql_queries.py +15 -2
  7. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/__init__.py +2 -0
  8. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/asset.py +13 -0
  9. castor_extractor-0.16.15/castor_extractor/warehouse/databricks/client.py +465 -0
  10. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/databricks/client_test.py +61 -1
  11. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/databricks/extract.py +36 -0
  12. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/databricks/format.py +13 -0
  13. castor_extractor-0.16.15/castor_extractor/warehouse/databricks/test_constants.py +79 -0
  14. castor_extractor-0.16.15/castor_extractor/warehouse/databricks/types.py +8 -0
  15. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/salesforce/client.py +8 -6
  16. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/salesforce/extract.py +2 -2
  17. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/salesforce/format.py +34 -7
  18. castor_extractor-0.16.15/castor_extractor/warehouse/salesforce/format_test.py +80 -0
  19. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/extract.py +2 -0
  20. castor_extractor-0.16.15/castor_extractor/warehouse/snowflake/queries/function.sql +10 -0
  21. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/pyproject.toml +1 -1
  22. castor_extractor-0.16.9/castor_extractor/warehouse/databricks/client.py +0 -229
  23. castor_extractor-0.16.9/castor_extractor/warehouse/databricks/types.py +0 -3
  24. castor_extractor-0.16.9/castor_extractor/warehouse/salesforce/format_test.py +0 -32
  25. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/Dockerfile +0 -0
  26. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/LICENCE +0 -0
  27. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/README.md +0 -0
  28. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/__init__.py +0 -0
  29. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/__init__.py +0 -0
  30. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_bigquery.py +0 -0
  31. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_databricks.py +0 -0
  32. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_domo.py +0 -0
  33. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_looker.py +0 -0
  34. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_metabase_api.py +0 -0
  35. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_metabase_db.py +0 -0
  36. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_mode.py +0 -0
  37. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_mysql.py +0 -0
  38. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_postgres.py +0 -0
  39. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_powerbi.py +0 -0
  40. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_qlik.py +0 -0
  41. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_redshift.py +0 -0
  42. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_salesforce.py +0 -0
  43. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_salesforce_reporting.py +0 -0
  44. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_sigma.py +0 -0
  45. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_snowflake.py +0 -0
  46. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_sqlserver.py +0 -0
  47. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/extract_tableau.py +0 -0
  48. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/file_check.py +0 -0
  49. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/commands/upload.py +0 -0
  50. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/__init__.py +0 -0
  51. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/column.py +0 -0
  52. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/column_test.py +0 -0
  53. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/constants.py +0 -0
  54. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/enums.py +0 -0
  55. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/file.py +0 -0
  56. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/file_test.py +0 -0
  57. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/file_test_users.csv +0 -0
  58. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
  59. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/templates/__init__.py +0 -0
  60. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
  61. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/logger.py +0 -0
  62. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/types.py +0 -0
  63. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/__init__.py +0 -0
  64. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/constant.py +0 -0
  65. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/env.py +0 -0
  66. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/env_test.py +0 -0
  67. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/upload.py +0 -0
  68. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/upload_test.py +0 -0
  69. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/uploader/utils.py +0 -0
  70. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/__init__.py +0 -0
  71. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/__init__.py +0 -0
  72. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/abstract.py +0 -0
  73. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/api_test.py +0 -0
  74. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/postgres.py +0 -0
  75. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/query.py +0 -0
  76. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/uri.py +0 -0
  77. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/client/uri_test.py +0 -0
  78. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/collection.py +0 -0
  79. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/collection_test.py +0 -0
  80. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/constants.py +0 -0
  81. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/dbt/__init__.py +0 -0
  82. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/dbt/assets.py +0 -0
  83. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/dbt/client.py +0 -0
  84. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/dbt/client_test.py +0 -0
  85. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/dbt/credentials.py +0 -0
  86. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/deprecate.py +0 -0
  87. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/env.py +0 -0
  88. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/files.py +0 -0
  89. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/files_test.py +0 -0
  90. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/formatter.py +0 -0
  91. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/formatter_test.csv +0 -0
  92. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/formatter_test.json +0 -0
  93. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/formatter_test.py +0 -0
  94. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/json_stream_write.py +0 -0
  95. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/load.py +0 -0
  96. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/object.py +0 -0
  97. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/object_test.py +0 -0
  98. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/__init__.py +0 -0
  99. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/pager.py +0 -0
  100. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/pager_on_id.py +0 -0
  101. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/pager_on_id_test.py +0 -0
  102. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/pager_on_token.py +0 -0
  103. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/pager_on_token_test.py +0 -0
  104. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/pager/pager_test.py +0 -0
  105. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/retry_test.py +0 -0
  106. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/safe.py +0 -0
  107. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/safe_test.py +0 -0
  108. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/salesforce/__init__.py +0 -0
  109. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/salesforce/client.py +0 -0
  110. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/salesforce/client_test.py +0 -0
  111. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/salesforce/constants.py +0 -0
  112. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/salesforce/credentials.py +0 -0
  113. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/salesforce/credentials_test.py +0 -0
  114. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/store.py +0 -0
  115. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/string.py +0 -0
  116. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/string_test.py +0 -0
  117. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/time.py +0 -0
  118. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/time_test.py +0 -0
  119. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/type.py +0 -0
  120. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/validation.py +0 -0
  121. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/validation_test.py +0 -0
  122. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/utils/write.py +0 -0
  123. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/__init__.py +0 -0
  124. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/__init__.py +0 -0
  125. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/assets.py +0 -0
  126. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/__init__.py +0 -0
  127. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/client.py +0 -0
  128. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/client_test.py +0 -0
  129. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/credentials.py +0 -0
  130. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
  131. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/pagination.py +0 -0
  132. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/client/pagination_test.py +0 -0
  133. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/constants.py +0 -0
  134. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/domo/extract.py +0 -0
  135. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/__init__.py +0 -0
  136. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/__init__.py +0 -0
  137. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/client.py +0 -0
  138. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/client_test.py +0 -0
  139. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/constants.py +0 -0
  140. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/sdk.py +0 -0
  141. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
  142. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/api/utils.py +0 -0
  143. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/assets.py +0 -0
  144. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/constant.py +0 -0
  145. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/env.py +0 -0
  146. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/extract.py +0 -0
  147. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/fields.py +0 -0
  148. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/fields_test.py +0 -0
  149. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/multithreading.py +0 -0
  150. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/looker/parameters.py +0 -0
  151. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/__init__.py +0 -0
  152. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/assets.py +0 -0
  153. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
  154. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
  155. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
  156. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/api/client_test.py +0 -0
  157. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
  158. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
  159. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
  160. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
  161. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
  162. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
  163. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
  164. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
  165. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
  166. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
  167. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
  168. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
  169. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
  170. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
  171. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
  172. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/client/shared.py +0 -0
  173. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/errors.py +0 -0
  174. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/extract.py +0 -0
  175. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/metabase/types.py +0 -0
  176. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/__init__.py +0 -0
  177. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/assets.py +0 -0
  178. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/client/__init__.py +0 -0
  179. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/client/client.py +0 -0
  180. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/client/client_test.json +0 -0
  181. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/client/client_test.py +0 -0
  182. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/client/constants.py +0 -0
  183. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/client/credentials.py +0 -0
  184. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/errors.py +0 -0
  185. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/mode/extract.py +0 -0
  186. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/__init__.py +0 -0
  187. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/assets.py +0 -0
  188. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
  189. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
  190. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
  191. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
  192. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/rest.py +0 -0
  193. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/rest_test.py +0 -0
  194. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/utils.py +0 -0
  195. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/client/utils_test.py +0 -0
  196. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/powerbi/extract.py +0 -0
  197. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/__init__.py +0 -0
  198. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/assets.py +0 -0
  199. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
  200. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/constants.py +0 -0
  201. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
  202. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
  203. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
  204. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
  205. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
  206. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
  207. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
  208. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
  209. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/master.py +0 -0
  210. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/rest.py +0 -0
  211. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
  212. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/constants.py +0 -0
  213. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/qlik/extract.py +0 -0
  214. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/salesforce_reporting/__init__.py +0 -0
  215. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/salesforce_reporting/assets.py +0 -0
  216. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/salesforce_reporting/client/__init__.py +0 -0
  217. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/salesforce_reporting/client/rest.py +0 -0
  218. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/salesforce_reporting/client/soql.py +0 -0
  219. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/salesforce_reporting/extract.py +0 -0
  220. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/__init__.py +0 -0
  221. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/assets.py +0 -0
  222. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
  223. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/client/client.py +0 -0
  224. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/client/client_test.py +0 -0
  225. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
  226. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
  227. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
  228. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/constants.py +0 -0
  229. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/sigma/extract.py +0 -0
  230. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/__init__.py +0 -0
  231. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/assets.py +0 -0
  232. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/client/__init__.py +0 -0
  233. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/client/client.py +0 -0
  234. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/client/client_utils.py +0 -0
  235. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/client/credentials.py +0 -0
  236. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/client/project.py +0 -0
  237. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/client/safe_mode.py +0 -0
  238. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/constants.py +0 -0
  239. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/errors.py +0 -0
  240. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/extract.py +0 -0
  241. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/gql_fields.py +0 -0
  242. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/__init__.py +0 -0
  243. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/__init__.py +0 -0
  244. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_1_get.json +0 -0
  245. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_2_get.json +0 -0
  246. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/auth.xml +0 -0
  247. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/project_get.xml +0 -0
  248. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/user_get.xml +0 -0
  249. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/view_get_usage.xml +0 -0
  250. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/workbook_get.xml +0 -0
  251. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/graphql/__init__.py +0 -0
  252. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/graphql/paginated_object_test.py +0 -0
  253. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/__init__.py +0 -0
  254. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/auth_test.py +0 -0
  255. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/credentials_test.py +0 -0
  256. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/projects_test.py +0 -0
  257. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/usages_test.py +0 -0
  258. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/users_test.py +0 -0
  259. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/rest_api/workbooks_test.py +0 -0
  260. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/utils/__init__.py +0 -0
  261. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tests/unit/utils/env_key.py +0 -0
  262. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/tsc_fields.py +0 -0
  263. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/types.py +0 -0
  264. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau/usage.py +0 -0
  265. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/__init__.py +0 -0
  266. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/assets.py +0 -0
  267. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/client/__init__.py +0 -0
  268. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/client/credentials.py +0 -0
  269. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/client/errors.py +0 -0
  270. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/client/tsc_fields.py +0 -0
  271. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/constants.py +0 -0
  272. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/visualization/tableau_revamp/extract.py +0 -0
  273. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/__init__.py +0 -0
  274. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/asset_test.py +0 -0
  275. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/extract.py +0 -0
  276. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/query.py +0 -0
  277. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
  278. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
  279. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
  280. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/client.py +0 -0
  281. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/client_test.py +0 -0
  282. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/credentials.py +0 -0
  283. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/extract.py +0 -0
  284. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
  285. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
  286. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
  287. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
  288. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
  289. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
  290. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
  291. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
  292. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
  293. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
  294. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/query.py +0 -0
  295. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/bigquery/types.py +0 -0
  296. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/databricks/__init__.py +0 -0
  297. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/databricks/credentials.py +0 -0
  298. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/databricks/format_test.py +0 -0
  299. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/__init__.py +0 -0
  300. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/client.py +0 -0
  301. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/client_test.py +0 -0
  302. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/extract.py +0 -0
  303. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/.sqlfluff +0 -0
  304. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/column.sql +0 -0
  305. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/database.sql +0 -0
  306. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/query.sql +0 -0
  307. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/schema.sql +0 -0
  308. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/table.sql +0 -0
  309. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/user.sql +0 -0
  310. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/queries/view_ddl.sql +0 -0
  311. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/mysql/query.py +0 -0
  312. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/__init__.py +0 -0
  313. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/extract.py +0 -0
  314. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
  315. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
  316. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
  317. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
  318. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
  319. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
  320. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
  321. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/postgres/query.py +0 -0
  322. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/__init__.py +0 -0
  323. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/client.py +0 -0
  324. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/client_test.py +0 -0
  325. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/extract.py +0 -0
  326. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
  327. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
  328. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
  329. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
  330. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
  331. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
  332. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
  333. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
  334. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
  335. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -0
  336. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/redshift/query.py +0 -0
  337. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/salesforce/__init__.py +0 -0
  338. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/salesforce/constants.py +0 -0
  339. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/salesforce/soql.py +0 -0
  340. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
  341. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/client.py +0 -0
  342. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
  343. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/credentials.py +0 -0
  344. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/credentials_test.py +0 -0
  345. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
  346. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/column.sql +0 -0
  347. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
  348. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
  349. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
  350. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
  351. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/query.sql +0 -0
  352. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
  353. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/schema.sql +0 -0
  354. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/table.sql +0 -0
  355. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
  356. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
  357. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/snowflake/query.py +0 -0
  358. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/__init__.py +0 -0
  359. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/client.py +0 -0
  360. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/extract.py +0 -0
  361. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/queries/.sqlfluff +0 -0
  362. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/queries/column.sql +0 -0
  363. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/queries/database.sql +0 -0
  364. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/queries/schema.sql +0 -0
  365. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/queries/table.sql +0 -0
  366. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/queries/user.sql +0 -0
  367. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/sqlserver/query.py +0 -0
  368. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/__init__.py +0 -0
  369. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/extract.py +0 -0
  370. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/.sqlfluff +0 -0
  371. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/column.sql +0 -0
  372. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/database.sql +0 -0
  373. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/query.sql +0 -0
  374. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/schema.sql +0 -0
  375. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/table.sql +0 -0
  376. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/user.sql +0 -0
  377. {castor_extractor-0.16.9 → castor_extractor-0.16.15}/castor_extractor/warehouse/synapse/queries/view_ddl.sql +0 -0
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.16.15 - 2024-06-07
4
+
5
+ * Tableau: extract database_name for CustomSQLTables
6
+
7
+ ## 0.16.14 - 2024-06-06
8
+
9
+ * Snowflake: Extract SQL user defined function
10
+
11
+ ## 0.16.13 - 2024-06-05
12
+
13
+ * Tableau: extract database_name for tables
14
+
15
+ ## 0.16.12 - 2024-06-04
16
+
17
+ * Databricks: Extract lineage
18
+
19
+ ## 0.16.11 - 2024-06-03
20
+
21
+ * Tableau: add extra fields to optimise storage
22
+
23
+ ## 0.16.10 - 2024-05-30
24
+
25
+ * Salesforce: extract sobjects Label as table name
26
+
3
27
  ## 0.16.9 - 2024-05-28
4
28
 
5
29
  * Tableau: extract only fields that are necessary
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.16.9
3
+ Version: 0.16.15
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -5,7 +5,7 @@ import requests
5
5
 
6
6
  logger = logging.getLogger(__name__)
7
7
 
8
- DEFAULT_TIMEOUT_MS = 30_000
8
+ DEFAULT_TIMEOUT_S = 30
9
9
 
10
10
  # https://requests.readthedocs.io/en/latest/api/#requests.request
11
11
  HttpMethod = Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"]
@@ -20,7 +20,7 @@ class APIClient:
20
20
  def __init__(self, host: str, token: Optional[str] = None):
21
21
  self._host = host
22
22
  self._token = token or ""
23
- self._timeout = DEFAULT_TIMEOUT_MS
23
+ self._timeout = DEFAULT_TIMEOUT_S
24
24
 
25
25
  @staticmethod
26
26
  def build_url(host: str, path: str):
@@ -44,7 +44,12 @@ class APIClient:
44
44
  ) -> Any:
45
45
  logger.debug(f"Calling {method} on {url}")
46
46
  result = requests.request(
47
- method, url, headers=self._headers(), params=params, json=data
47
+ method,
48
+ url,
49
+ headers=self._headers(),
50
+ params=params,
51
+ json=data,
52
+ timeout=self._timeout,
48
53
  )
49
54
  result.raise_for_status()
50
55
 
@@ -68,7 +68,8 @@ class Retry(BaseModel):
68
68
  self._retry_attempts += 1
69
69
  wait_ms = self.base() + self.jitter()
70
70
  wait_s = float(wait_ms) / MS_IN_SEC
71
- logger.warning(f"Attempting a new call in {wait_s} seconds")
71
+ msg = f"Attempting a new call in {wait_s} seconds, {self._retry_attempts} attempt(s) / {self.max_retries} max retries"
72
+ logger.warning(msg)
72
73
  time.sleep(wait_s)
73
74
  return True
74
75
 
@@ -93,6 +94,7 @@ def retry(
93
94
  try:
94
95
  return None, callable(*args, **kwargs)
95
96
  except exceptions_ as err:
97
+ logger.warning(f"Exception within {callable.__name__}")
96
98
  return err, None
97
99
 
98
100
  def _func(*args, **kwargs) -> Any:
@@ -28,10 +28,16 @@ _TSC_ASSETS = (
28
28
  TableauRevampAsset.USAGE,
29
29
  )
30
30
 
31
- # speed up extraction: fields and columns are smaller but volumes are bigger
31
+ # increase the value when extraction is too slow
32
+ # decrease the value when timeouts arise
32
33
  _CUSTOM_PAGE_SIZE: Dict[TableauRevampAsset, int] = {
34
+ # for some clients, extraction of columns tend to hit the node limit
35
+ # https://community.tableau.com/s/question/0D54T00000YuK60SAF/metadata-query-nodelimitexceeded-error
36
+ # the workaround is to reduce pagination
37
+ TableauRevampAsset.COLUMN: 50,
38
+ # fields are light but volumes are bigger
33
39
  TableauRevampAsset.FIELD: 1000,
34
- TableauRevampAsset.COLUMN: 1000,
40
+ TableauRevampAsset.TABLE: 50,
35
41
  }
36
42
 
37
43
 
@@ -18,7 +18,11 @@ QUERY_TEMPLATE = """
18
18
 
19
19
  _COLUMNS_QUERY = """
20
20
  downstreamDashboards { id }
21
- downstreamFields { id }
21
+ downstreamFields {
22
+ id
23
+ __typename
24
+ datasource { id }
25
+ }
22
26
  downstreamWorkbooks { id }
23
27
  id
24
28
  name
@@ -59,12 +63,21 @@ downstreamWorkbooks { id }
59
63
  id
60
64
  name
61
65
  ... on DatabaseTable {
62
- connectionType
63
66
  fullName
64
67
  schema
68
+ database {
69
+ connectionType
70
+ id
71
+ name
72
+ }
65
73
  }
66
74
  ... on CustomSQLTable {
67
75
  query
76
+ database {
77
+ connectionType
78
+ id
79
+ name
80
+ }
68
81
  }
69
82
  """
70
83
 
@@ -1,6 +1,8 @@
1
1
  from .asset import (
2
+ ADDITIONAL_LINEAGE_ASSETS,
2
3
  CATALOG_ASSETS,
3
4
  EXTERNAL_LINEAGE_ASSETS,
5
+ FUNCTIONS_ASSETS,
4
6
  QUERIES_ASSETS,
5
7
  VIEWS_ASSETS,
6
8
  SupportedAssets,
@@ -7,6 +7,8 @@ from ...types import ExternalAsset, classproperty
7
7
  class WarehouseAsset(ExternalAsset):
8
8
  """Assets that can be extracted from warehouses"""
9
9
 
10
+ ADDITIONAL_COLUMN_LINEAGE = "additional_column_lineage"
11
+ ADDITIONAL_TABLE_LINEAGE = "additional_table_lineage"
10
12
  COLUMN = "column"
11
13
  COLUMN_LINEAGE = "column_lineage" # specific to snowflake
12
14
  DATABASE = "database"
@@ -19,12 +21,15 @@ class WarehouseAsset(ExternalAsset):
19
21
  ROLE = "role"
20
22
  SCHEMA = "schema"
21
23
  TABLE = "table"
24
+ FUNCTION = "function"
22
25
  USER = "user"
23
26
  VIEW_DDL = "view_ddl"
24
27
 
25
28
  @classproperty
26
29
  def optional(cls) -> Set["WarehouseAsset"]:
27
30
  return {
31
+ WarehouseAsset.ADDITIONAL_COLUMN_LINEAGE,
32
+ WarehouseAsset.ADDITIONAL_TABLE_LINEAGE,
28
33
  WarehouseAsset.EXTERNAL_COLUMN_LINEAGE,
29
34
  WarehouseAsset.EXTERNAL_TABLE_LINEAGE,
30
35
  }
@@ -33,8 +38,10 @@ class WarehouseAsset(ExternalAsset):
33
38
  class WarehouseAssetGroup(Enum):
34
39
  """Groups of assets that can be extracted together"""
35
40
 
41
+ ADDITIONAL_LINEAGE = "additional_lineage"
36
42
  CATALOG = "catalog"
37
43
  EXTERNAL_LINEAGE = "external_lineage"
44
+ FUNCTION = "function"
38
45
  QUERY = "query"
39
46
  ROLE = "role"
40
47
  SNOWFLAKE_LINEAGE = "snowflake_lineage"
@@ -53,6 +60,7 @@ CATALOG_ASSETS = (
53
60
  )
54
61
 
55
62
  # shared by technologies supporting queries
63
+ FUNCTIONS_ASSETS = (WarehouseAsset.FUNCTION,)
56
64
  QUERIES_ASSETS = (WarehouseAsset.QUERY,)
57
65
  VIEWS_ASSETS = (WarehouseAsset.VIEW_DDL,)
58
66
 
@@ -61,6 +69,11 @@ EXTERNAL_LINEAGE_ASSETS = (
61
69
  WarehouseAsset.EXTERNAL_TABLE_LINEAGE,
62
70
  )
63
71
 
72
+ ADDITIONAL_LINEAGE_ASSETS = (
73
+ WarehouseAsset.ADDITIONAL_COLUMN_LINEAGE,
74
+ WarehouseAsset.ADDITIONAL_TABLE_LINEAGE,
75
+ )
76
+
64
77
  NON_EXTRACTABLE_ASSETS = {WarehouseAssetGroup.EXTERNAL_LINEAGE}
65
78
 
66
79
 
@@ -0,0 +1,465 @@
1
+ import logging
2
+ from concurrent.futures import ThreadPoolExecutor
3
+ from datetime import date
4
+ from functools import partial
5
+ from typing import Any, Dict, List, Optional, Set, Tuple, cast
6
+
7
+ import requests
8
+
9
+ from ...utils import (
10
+ SafeMode,
11
+ at_midnight,
12
+ date_after,
13
+ mapping_from_rows,
14
+ retry,
15
+ safe_mode,
16
+ )
17
+ from ...utils.client.api import APIClient
18
+ from ...utils.pager import PagerOnToken
19
+ from ..abstract.time_filter import TimeFilter
20
+ from .credentials import DatabricksCredentials
21
+ from .format import DatabricksFormatter
22
+ from .types import Link, Ostr, OTimestampedLink, TablesColumns, TimestampedLink
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+ _MAX_NUMBER_OF_LINEAGE_ERRORS = 1000
27
+ _MAX_THREADS = 10
28
+ _RETRY_ATTEMPTS = 3
29
+ _RETRY_BASE_MS = 1000
30
+ _RETRY_EXCEPTIONS = [
31
+ requests.exceptions.ConnectTimeout,
32
+ ]
33
+
34
+ safe_params = SafeMode((BaseException,), _MAX_NUMBER_OF_LINEAGE_ERRORS)
35
+
36
+
37
+ def _day_to_epoch_ms(day: date) -> int:
38
+ return int(at_midnight(day).timestamp() * 1000)
39
+
40
+
41
+ def _day_hour_to_epoch_ms(day: date, hour: int) -> int:
42
+ return int(at_midnight(day).timestamp() * 1000) + (hour * 3600 * 1000)
43
+
44
+
45
+ class LineageLinks:
46
+ """
47
+ helper class that handles lineage deduplication and filtering
48
+ """
49
+
50
+ def __init__(self):
51
+ self.lineage: Dict[Link, Ostr] = dict()
52
+
53
+ def add(self, timestamped_link: TimestampedLink) -> None:
54
+ """
55
+ keep the most recent lineage link, adding to `self.lineage`
56
+ """
57
+ parent, child, timestamp = timestamped_link
58
+ link = (parent, child)
59
+ if not self.lineage.get(link):
60
+ self.lineage[link] = timestamp
61
+ else:
62
+ if not timestamp:
63
+ return
64
+ # keep most recent link; cast for mypy
65
+ recent = max(cast(str, self.lineage[link]), cast(str, timestamp))
66
+ self.lineage[link] = recent
67
+
68
+
69
+ class DatabricksClient(APIClient):
70
+ """Databricks Client"""
71
+
72
+ def __init__(
73
+ self,
74
+ credentials: DatabricksCredentials,
75
+ db_allowed: Optional[Set[str]] = None,
76
+ db_blocked: Optional[Set[str]] = None,
77
+ ):
78
+ super().__init__(host=credentials.host, token=credentials.token)
79
+ self._db_allowed = db_allowed
80
+ self._db_blocked = db_blocked
81
+ self.formatter = DatabricksFormatter()
82
+
83
+ @staticmethod
84
+ def name() -> str:
85
+ return "Databricks"
86
+
87
+ def _keep_catalog(self, catalog: str) -> bool:
88
+ """
89
+ Helper function to determine if we should keep the Databricks catalog
90
+ which is a CastorDoc database
91
+ """
92
+ if self._db_allowed and catalog not in self._db_allowed:
93
+ return False
94
+ if self._db_blocked and catalog in self._db_blocked:
95
+ return False
96
+ return True
97
+
98
+ def databases(self) -> List[dict]:
99
+ path = "api/2.1/unity-catalog/catalogs"
100
+ content = self.get(path=path)
101
+ _databases = self.formatter.format_database(content.get("catalogs", []))
102
+ return [d for d in _databases if self._keep_catalog(d["database_name"])]
103
+
104
+ def _schemas_of_database(self, database: dict) -> List[dict]:
105
+ path = "api/2.1/unity-catalog/schemas"
106
+ payload = {"catalog_name": database["database_name"]}
107
+ content = self.get(path=path, payload=payload)
108
+ schemas = content.get("schemas", [])
109
+ return self.formatter.format_schema(schemas, database)
110
+
111
+ def schemas(self, databases: List[dict]) -> List[dict]:
112
+ """
113
+ Get the databricks schemas (also sometimes called databases)
114
+ (which correspond to the schemas in Castor)
115
+ leveraging the unity catalog API
116
+ """
117
+ return [
118
+ schema
119
+ for database in databases
120
+ for schema in self._schemas_of_database(database)
121
+ ]
122
+
123
+ def _tables_columns_of_schema(self, schema: dict) -> TablesColumns:
124
+ path = "api/2.1/unity-catalog/tables"
125
+ payload = {
126
+ "catalog_name": schema["database_id"],
127
+ "schema_name": schema["schema_name"],
128
+ }
129
+ content = self.get(path=path, payload=payload)
130
+ return self.formatter.format_table_column(
131
+ content.get("tables", []), schema
132
+ )
133
+
134
+ @staticmethod
135
+ def _match_table_with_user(table: dict, user_mapping: dict) -> dict:
136
+ table_owner_email = table.get("owner_email")
137
+ if not table_owner_email:
138
+ return table
139
+ owner_external_id = user_mapping.get(table_owner_email)
140
+ if not owner_external_id:
141
+ return table
142
+ return {**table, "owner_external_id": owner_external_id}
143
+
144
+ @staticmethod
145
+ def _get_user_mapping(users: List[dict]) -> dict:
146
+ return {
147
+ **mapping_from_rows(users, "email", "id"),
148
+ **mapping_from_rows(users, "user_name", "id"),
149
+ }
150
+
151
+ def tables_and_columns(
152
+ self, schemas: List[dict], users: List[dict]
153
+ ) -> TablesColumns:
154
+ """
155
+ Get the databricks tables & columns leveraging the unity catalog API
156
+ """
157
+ tables: List[dict] = []
158
+ columns: List[dict] = []
159
+ user_mapping = self._get_user_mapping(users)
160
+ for schema in schemas:
161
+ t_to_add, c_to_add = self._tables_columns_of_schema(schema)
162
+ t_with_owner = [
163
+ self._match_table_with_user(table, user_mapping)
164
+ for table in t_to_add
165
+ ]
166
+ tables.extend(t_with_owner)
167
+ columns.extend(c_to_add)
168
+ return tables, columns
169
+
170
+ @staticmethod
171
+ def _to_table_path(table: dict) -> Ostr:
172
+ if table.get("name"):
173
+ return f"{table['catalog_name']}.{table['schema_name']}.{table['name']}"
174
+ return None
175
+
176
+ @staticmethod
177
+ def _to_column_path(column: dict) -> Ostr:
178
+ if column.get("name"):
179
+ return f"{column['catalog_name']}.{column['schema_name']}.{column['table_name']}.{column['name']}"
180
+ return None
181
+
182
+ def _link(
183
+ self, path_from: Ostr, path_to: Ostr, timestamp: Ostr
184
+ ) -> OTimestampedLink:
185
+ """exclude missing path and self-lineage"""
186
+ if (not path_from) or (not path_to):
187
+ return None
188
+ is_self_lineage = path_from.lower() == path_to.lower()
189
+ if is_self_lineage:
190
+ return None
191
+ return (path_from, path_to, timestamp)
192
+
193
+ def _single_table_lineage_links(
194
+ self, table_path: str, single_table_lineage: dict
195
+ ) -> List[TimestampedLink]:
196
+ """
197
+ process databricks lineage API response for a given table
198
+ returns a list of (parent, child, timestamp)
199
+
200
+ Note: in `upstreams` or `downstreams` we only care about `tableInfo`,
201
+ we could also have `notebookInfos` or `fileInfo`
202
+ """
203
+ links: List[OTimestampedLink] = []
204
+ # add parent:
205
+ for link in single_table_lineage.get("upstreams", []):
206
+ parent = link.get("tableInfo", {})
207
+ parent_path = self._to_table_path(parent)
208
+ timestamp: Ostr = parent.get("lineage_timestamp")
209
+ links.append(self._link(parent_path, table_path, timestamp))
210
+
211
+ # add children:
212
+ for link in single_table_lineage.get("downstreams", []):
213
+ child = link.get("tableInfo", {})
214
+ child_path = self._to_table_path(child)
215
+ timestamp = child.get("lineage_timestamp")
216
+ links.append(self._link(table_path, child_path, timestamp))
217
+
218
+ return list(filter(None, links))
219
+
220
+ @safe_mode(safe_params, lambda: [])
221
+ @retry(
222
+ exceptions=_RETRY_EXCEPTIONS,
223
+ max_retries=_RETRY_ATTEMPTS,
224
+ base_ms=_RETRY_BASE_MS,
225
+ )
226
+ def get_single_table_lineage(
227
+ self, table_path: str
228
+ ) -> List[TimestampedLink]:
229
+ """
230
+ Helper function used in get_lineage_links.
231
+ Call data lineage API and return the content of the result
232
+ eg table_path: broward_prd.bronze.account_adjustments
233
+ FYI: Maximum rate of 50 requests per SECOND
234
+ """
235
+ path = "api/2.0/lineage-tracking/table-lineage"
236
+ payload = {"table_name": table_path, "include_entity_lineage": True}
237
+ content = self.get(path=path, payload=payload)
238
+ return self._single_table_lineage_links(table_path, content)
239
+
240
+ def _deduplicate_lineage(self, lineages: List[TimestampedLink]) -> dict:
241
+ deduplicated_lineage = LineageLinks()
242
+ for timestamped_link in lineages:
243
+ deduplicated_lineage.add(timestamped_link)
244
+ return deduplicated_lineage.lineage
245
+
246
+ def table_lineage(self, tables: List[dict]) -> List[dict]:
247
+ """
248
+ Wrapper function that retrieves all table lineage
249
+ """
250
+ # retrieve table lineage
251
+ with ThreadPoolExecutor(max_workers=_MAX_THREADS) as executor:
252
+ table_paths = [
253
+ ".".join([table["schema_id"], table["table_name"]])
254
+ for table in tables
255
+ ]
256
+ results = executor.map(self.get_single_table_lineage, table_paths)
257
+ lineages = [link for links in results for link in links]
258
+ deduplicated = self._deduplicate_lineage(lineages)
259
+ return self.formatter.format_lineage(deduplicated)
260
+
261
+ @staticmethod
262
+ def _paths_for_column_lineage(
263
+ tables: List[dict], columns: List[dict], table_lineage: List[dict]
264
+ ) -> List[Tuple[str, str]]:
265
+ """
266
+ helper providing a list of candidate columns to look lineage for:
267
+ we only look for column lineage where there is table lineage
268
+ """
269
+ # mapping between table id and its path db.schema.table
270
+ # table["schema_id"] follows the pattern `db.schema`
271
+ mapping = {
272
+ table["id"]: ".".join([table["schema_id"], table["table_name"]])
273
+ for table in tables
274
+ }
275
+
276
+ tables_with_lineage: Set[str] = set()
277
+ for t in table_lineage:
278
+ tables_with_lineage.add(t["parent_path"])
279
+ tables_with_lineage.add(t["child_path"])
280
+
281
+ paths_to_return: List[Tuple[str, str]] = []
282
+ for column in columns:
283
+ table_path = mapping[column["table_id"]]
284
+ if table_path not in tables_with_lineage:
285
+ continue
286
+ column_ = (table_path, column["column_name"])
287
+ paths_to_return.append(column_)
288
+
289
+ return paths_to_return
290
+
291
+ def _single_column_lineage_links(
292
+ self, column_path: str, single_column_lineage: dict
293
+ ) -> List[TimestampedLink]:
294
+ """
295
+ process databricks lineage API response for a given table
296
+ returns a list of (parent, child, timestamp)
297
+
298
+ Note: in `upstreams` or `downstreams` we only care about `tableInfo`,
299
+ we could also have `notebookInfos` or `fileInfo`
300
+ """
301
+ links: List[OTimestampedLink] = []
302
+ # add parent:
303
+ for link in single_column_lineage.get("upstream_cols", []):
304
+ parent_path = self._to_column_path(link)
305
+ timestamp: Ostr = link.get("lineage_timestamp")
306
+ links.append(self._link(parent_path, column_path, timestamp))
307
+
308
+ # add children:
309
+ for link in single_column_lineage.get("downstream_cols", []):
310
+ child_path = self._to_column_path(link)
311
+ timestamp = link.get("lineage_timestamp")
312
+ links.append(self._link(column_path, child_path, timestamp))
313
+
314
+ return list(filter(None, links))
315
+
316
+ @safe_mode(safe_params, lambda: [])
317
+ @retry(
318
+ exceptions=_RETRY_EXCEPTIONS,
319
+ max_retries=_RETRY_ATTEMPTS,
320
+ base_ms=_RETRY_BASE_MS,
321
+ )
322
+ def get_single_column_lineage(
323
+ self,
324
+ names: Tuple[str, str],
325
+ ) -> List[TimestampedLink]:
326
+ """
327
+ Helper function used in get_lineage_links.
328
+ Call data lineage API and return the content of the result
329
+
330
+ eg table_path: broward_prd.bronze.account_adjustments
331
+ FYI: Maximum rate of 10 requests per SECOND
332
+ """
333
+ table_path, column_name = names
334
+ api_path = "api/2.0/lineage-tracking/column-lineage"
335
+ payload = {
336
+ "table_name": table_path,
337
+ "column_name": column_name,
338
+ "include_entity_lineage": True,
339
+ }
340
+ content = self.get(path=api_path, payload=payload)
341
+ column_path = f"{table_path}.{column_name}"
342
+ return self._single_column_lineage_links(column_path, content)
343
+
344
+ def column_lineage(
345
+ self, tables: List[dict], columns: List[dict], table_lineage: List[dict]
346
+ ) -> List[dict]:
347
+ """
348
+ Wrapper function that retrieves all column lineage
349
+ we only try to retrieve column lineage if we found table lineage
350
+ """
351
+ candidate_paths = self._paths_for_column_lineage(
352
+ tables, columns, table_lineage
353
+ )
354
+ lineages: List[TimestampedLink] = [
355
+ link
356
+ for paths in candidate_paths
357
+ for link in self.get_single_column_lineage(paths)
358
+ ]
359
+ deduplicated = self._deduplicate_lineage(lineages)
360
+ return self.formatter.format_lineage(deduplicated)
361
+
362
+ @staticmethod
363
+ def _time_filter(time_filter: Optional[TimeFilter]) -> dict:
364
+ """time filter to retrieve Databricks' queries"""
365
+ # define an explicit time window
366
+ if not time_filter:
367
+ time_filter = TimeFilter.default()
368
+
369
+ assert time_filter # for mypy
370
+
371
+ hour_min = time_filter.hour_min
372
+ hour_max = time_filter.hour_max
373
+ day = time_filter.day
374
+ if hour_min is not None and hour_max is not None: # specific window
375
+ start_time_ms = _day_hour_to_epoch_ms(day, hour_min)
376
+ # note: in practice, hour_min == hour_max (hourly query ingestion)
377
+ end_time_ms = _day_hour_to_epoch_ms(day, hour_max + 1)
378
+ else: # fallback to an extraction of the entire day
379
+ start_time_ms = _day_to_epoch_ms(day)
380
+ end_time_ms = _day_to_epoch_ms(date_after(day, 1))
381
+
382
+ return {
383
+ "filter_by": {
384
+ "query_start_time_range": {
385
+ "end_time_ms": end_time_ms,
386
+ "start_time_ms": start_time_ms,
387
+ }
388
+ }
389
+ }
390
+
391
+ def query_payload(
392
+ self,
393
+ page_token: Optional[str] = None,
394
+ max_results: Optional[int] = None,
395
+ time_range_filter: Optional[dict] = None,
396
+ ) -> dict:
397
+ """helper method to build the payload used to retrieve queries"""
398
+ # in payload: You can provide only one of 'page_token' or 'filter_by'
399
+ if page_token:
400
+ payload: Dict[str, Any] = {"page_token": page_token}
401
+ else:
402
+ if time_range_filter:
403
+ payload = {**time_range_filter}
404
+ else:
405
+ payload = self._time_filter(None) # default to yesterday
406
+ if max_results:
407
+ payload["max_results"] = max_results
408
+ return payload
409
+
410
+ def _scroll_queries(
411
+ self,
412
+ page_token: Optional[str] = None,
413
+ max_results: Optional[int] = None,
414
+ time_range_filter: Optional[dict] = None,
415
+ ) -> dict:
416
+ """
417
+ Callback to scroll the queries api
418
+ https://docs.databricks.com/api/workspace/queryhistory/list
419
+ max_results: Limit the number of results returned in one page.
420
+ The default is 100. (both on our side and Databricks')
421
+ """
422
+ path = "api/2.0/sql/history/queries"
423
+ payload = self.query_payload(page_token, max_results, time_range_filter)
424
+ content = self.get(path=path, payload=payload)
425
+ return content if content else {}
426
+
427
+ def queries(self, time_filter: Optional[TimeFilter] = None) -> List[dict]:
428
+ """get all queries"""
429
+ # add a time filter (by default: yesterday)
430
+ time_range_filter = self._time_filter(time_filter)
431
+ _time_filtered_scroll_queries = partial(
432
+ self._scroll_queries,
433
+ time_range_filter=time_range_filter,
434
+ )
435
+
436
+ # retrieve all queries using pagination
437
+ raw_queries = PagerOnToken(_time_filtered_scroll_queries).all()
438
+
439
+ return self.formatter.format_query(raw_queries)
440
+
441
+ def users(self) -> List[dict]:
442
+ """
443
+ retrieve user from api
444
+ """
445
+ path = "api/2.0/preview/scim/v2/Users"
446
+ content = self.get(path=path)
447
+ return self.formatter.format_user(content.get("Resources", []))
448
+
449
+ def _view_ddl(self, schema: dict) -> List[dict]:
450
+ path = "api/2.1/unity-catalog/tables"
451
+ payload = {
452
+ "catalog_name": schema["database_id"],
453
+ "schema_name": schema["schema_name"],
454
+ "omit_columns": True,
455
+ }
456
+ content = self.get(path=path, payload=payload)
457
+ return self.formatter.format_view_ddl(content.get("tables", []), schema)
458
+
459
+ def view_ddl(self, schemas: List[dict]) -> List[dict]:
460
+ """retrieve view ddl"""
461
+ view_ddl: List[dict] = []
462
+ for schema in schemas:
463
+ v_to_add = self._view_ddl(schema)
464
+ view_ddl.extend(v_to_add)
465
+ return view_ddl