castor-extractor 0.22.1__tar.gz → 0.22.5__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 (444) hide show
  1. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/CHANGELOG.md +16 -0
  2. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/PKG-INFO +17 -1
  3. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/client.py +64 -10
  4. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/assets.py +3 -1
  5. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/client.py +67 -14
  6. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/utils.py +10 -4
  7. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/utils_test.py +22 -4
  8. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/api_client.py +2 -60
  9. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/client.py +4 -47
  10. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/client_test.py +1 -35
  11. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/credentials.py +4 -6
  12. castor_extractor-0.22.5/castor_extractor/warehouse/databricks/enums.py +15 -0
  13. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/extract.py +13 -11
  14. castor_extractor-0.22.5/castor_extractor/warehouse/databricks/lineage.py +69 -0
  15. castor_extractor-0.22.5/castor_extractor/warehouse/databricks/lineage_test.py +89 -0
  16. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/sql_client.py +23 -8
  17. castor_extractor-0.22.5/castor_extractor/warehouse/databricks/types.py +1 -0
  18. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/pyproject.toml +1 -1
  19. castor_extractor-0.22.1/castor_extractor/warehouse/databricks/lineage.py +0 -141
  20. castor_extractor-0.22.1/castor_extractor/warehouse/databricks/lineage_test.py +0 -34
  21. castor_extractor-0.22.1/castor_extractor/warehouse/databricks/test_constants.py +0 -79
  22. castor_extractor-0.22.1/castor_extractor/warehouse/databricks/types.py +0 -8
  23. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/Dockerfile +0 -0
  24. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/DockerfileUsage.md +0 -0
  25. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/LICENCE +0 -0
  26. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/README.md +0 -0
  27. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/__init__.py +0 -0
  28. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/__init__.py +0 -0
  29. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_bigquery.py +0 -0
  30. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_confluence.py +0 -0
  31. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_databricks.py +0 -0
  32. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_domo.py +0 -0
  33. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_looker.py +0 -0
  34. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_metabase_api.py +0 -0
  35. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_metabase_db.py +0 -0
  36. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_mode.py +0 -0
  37. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_mysql.py +0 -0
  38. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_notion.py +0 -0
  39. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_postgres.py +0 -0
  40. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_powerbi.py +0 -0
  41. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_qlik.py +0 -0
  42. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_redshift.py +0 -0
  43. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_salesforce.py +0 -0
  44. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_salesforce_reporting.py +0 -0
  45. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_sigma.py +0 -0
  46. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_snowflake.py +0 -0
  47. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_sqlserver.py +0 -0
  48. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_tableau.py +0 -0
  49. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_thoughtspot.py +0 -0
  50. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/file_check.py +0 -0
  51. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/upload.py +0 -0
  52. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/__init__.py +0 -0
  53. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/column.py +0 -0
  54. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/column_test.py +0 -0
  55. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/constants.py +0 -0
  56. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/enums.py +0 -0
  57. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file.py +0 -0
  58. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file_test.py +0 -0
  59. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file_test_users.csv +0 -0
  60. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
  61. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/templates/__init__.py +0 -0
  62. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
  63. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/__init__.py +0 -0
  64. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/__init__.py +0 -0
  65. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/assets.py +0 -0
  66. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/__init__.py +0 -0
  67. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/client.py +0 -0
  68. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/credentials.py +0 -0
  69. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/endpoints.py +0 -0
  70. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/pagination.py +0 -0
  71. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/extract.py +0 -0
  72. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/__init__.py +0 -0
  73. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/assets.py +0 -0
  74. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/__init__.py +0 -0
  75. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/client.py +0 -0
  76. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/client_test.py +0 -0
  77. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/constants.py +0 -0
  78. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/credentials.py +0 -0
  79. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/endpoints.py +0 -0
  80. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/pagination.py +0 -0
  81. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/extract.py +0 -0
  82. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/logger.py +0 -0
  83. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/__init__.py +0 -0
  84. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/__init__.py +0 -0
  85. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/assets.py +0 -0
  86. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/__init__.py +0 -0
  87. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/client.py +0 -0
  88. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/credentials.py +0 -0
  89. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/endpoints.py +0 -0
  90. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/pagination.py +0 -0
  91. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/types.py +0 -0
  92. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/__init__.py +0 -0
  93. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/constant.py +0 -0
  94. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/env.py +0 -0
  95. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/env_test.py +0 -0
  96. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/settings.py +0 -0
  97. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/upload.py +0 -0
  98. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/upload_test.py +0 -0
  99. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/utils.py +0 -0
  100. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/__init__.py +0 -0
  101. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/argument_parser.py +0 -0
  102. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/argument_parser_test.py +0 -0
  103. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/__init__.py +0 -0
  104. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/abstract.py +0 -0
  105. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/__init__.py +0 -0
  106. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/auth.py +0 -0
  107. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/auth_test.py +0 -0
  108. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/client.py +0 -0
  109. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/client_test.py +0 -0
  110. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/pagination.py +0 -0
  111. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/pagination_test.py +0 -0
  112. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/safe_request.py +0 -0
  113. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/safe_request_test.py +0 -0
  114. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/utils.py +0 -0
  115. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/utils_test.py +0 -0
  116. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/postgres.py +0 -0
  117. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/query.py +0 -0
  118. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/uri.py +0 -0
  119. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/uri_test.py +0 -0
  120. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/collection.py +0 -0
  121. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/collection_test.py +0 -0
  122. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/constants.py +0 -0
  123. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/__init__.py +0 -0
  124. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/assets.py +0 -0
  125. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/client.py +0 -0
  126. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/client_test.py +0 -0
  127. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/credentials.py +0 -0
  128. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/deprecate.py +0 -0
  129. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/env.py +0 -0
  130. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/files.py +0 -0
  131. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/files_test.py +0 -0
  132. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter.py +0 -0
  133. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter_test.csv +0 -0
  134. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter_test.json +0 -0
  135. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter_test.py +0 -0
  136. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/json_stream_write.py +0 -0
  137. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/load.py +0 -0
  138. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/object.py +0 -0
  139. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/object_test.py +0 -0
  140. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/__init__.py +0 -0
  141. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager.py +0 -0
  142. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager_on_id.py +0 -0
  143. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager_on_id_test.py +0 -0
  144. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager_test.py +0 -0
  145. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/retry.py +0 -0
  146. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/retry_test.py +0 -0
  147. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/safe.py +0 -0
  148. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/safe_test.py +0 -0
  149. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/__init__.py +0 -0
  150. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/client.py +0 -0
  151. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/client_test.py +0 -0
  152. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/constants.py +0 -0
  153. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/credentials.py +0 -0
  154. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/credentials_test.py +0 -0
  155. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/pagination.py +0 -0
  156. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/store.py +0 -0
  157. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/string.py +0 -0
  158. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/string_test.py +0 -0
  159. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/time.py +0 -0
  160. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/time_test.py +0 -0
  161. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/type.py +0 -0
  162. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/validation.py +0 -0
  163. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/validation_test.py +0 -0
  164. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/write.py +0 -0
  165. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/__init__.py +0 -0
  166. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/__init__.py +0 -0
  167. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/assets.py +0 -0
  168. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/__init__.py +0 -0
  169. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/client.py +0 -0
  170. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/credentials.py +0 -0
  171. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
  172. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/pagination.py +0 -0
  173. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/pagination_test.py +0 -0
  174. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/extract.py +0 -0
  175. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/__init__.py +0 -0
  176. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/__init__.py +0 -0
  177. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/client.py +0 -0
  178. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/client_test.py +0 -0
  179. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/constants.py +0 -0
  180. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/credentials.py +0 -0
  181. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/extraction_parameters.py +0 -0
  182. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/sdk.py +0 -0
  183. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
  184. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/utils.py +0 -0
  185. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/assets.py +0 -0
  186. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/constant.py +0 -0
  187. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/constants.py +0 -0
  188. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/extract.py +0 -0
  189. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/fields.py +0 -0
  190. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/fields_test.py +0 -0
  191. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/multithreading.py +0 -0
  192. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/__init__.py +0 -0
  193. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/assets.py +0 -0
  194. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/__init__.py +0 -0
  195. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +0 -0
  196. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/client.py +0 -0
  197. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/credentials.py +0 -0
  198. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/endpoints.py +0 -0
  199. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/enums.py +0 -0
  200. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +0 -0
  201. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/pagination.py +0 -0
  202. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/scopes.py +0 -0
  203. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/__init__.py +0 -0
  204. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/assets.py +0 -0
  205. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
  206. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
  207. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
  208. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/client_test.py +0 -0
  209. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
  210. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
  211. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
  212. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
  213. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
  214. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
  215. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
  216. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
  217. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
  218. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
  219. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
  220. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
  221. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
  222. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
  223. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
  224. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/shared.py +0 -0
  225. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/errors.py +0 -0
  226. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/extract.py +0 -0
  227. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/types.py +0 -0
  228. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/__init__.py +0 -0
  229. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/assets.py +0 -0
  230. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/__init__.py +0 -0
  231. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/client.py +0 -0
  232. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/client_test.json +0 -0
  233. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/client_test.py +0 -0
  234. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/constants.py +0 -0
  235. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/credentials.py +0 -0
  236. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/errors.py +0 -0
  237. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/extract.py +0 -0
  238. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/__init__.py +0 -0
  239. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/assets.py +0 -0
  240. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
  241. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/authentication.py +0 -0
  242. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/client.py +0 -0
  243. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/client_test.py +0 -0
  244. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
  245. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
  246. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
  247. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/endpoints.py +0 -0
  248. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/pagination.py +0 -0
  249. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/extract.py +0 -0
  250. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/__init__.py +0 -0
  251. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/assets.py +0 -0
  252. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
  253. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/constants.py +0 -0
  254. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
  255. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
  256. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
  257. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/credentials.py +0 -0
  258. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
  259. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
  260. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
  261. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
  262. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
  263. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/master.py +0 -0
  264. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/rest.py +0 -0
  265. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
  266. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/extract.py +0 -0
  267. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/__init__.py +0 -0
  268. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/assets.py +0 -0
  269. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/client/__init__.py +0 -0
  270. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/client/rest.py +0 -0
  271. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/client/soql.py +0 -0
  272. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/extract.py +0 -0
  273. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/__init__.py +0 -0
  274. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/assets.py +0 -0
  275. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
  276. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
  277. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
  278. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
  279. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/extract.py +0 -0
  280. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/__init__.py +0 -0
  281. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/assets.py +0 -0
  282. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/__init__.py +0 -0
  283. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/client.py +0 -0
  284. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/client_utils.py +0 -0
  285. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/credentials.py +0 -0
  286. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/project.py +0 -0
  287. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/safe_mode.py +0 -0
  288. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/constants.py +0 -0
  289. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/errors.py +0 -0
  290. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/extract.py +0 -0
  291. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/gql_fields.py +0 -0
  292. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/__init__.py +0 -0
  293. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/__init__.py +0 -0
  294. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_1_get.json +0 -0
  295. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_2_get.json +0 -0
  296. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/auth.xml +0 -0
  297. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/project_get.xml +0 -0
  298. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/user_get.xml +0 -0
  299. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/view_get_usage.xml +0 -0
  300. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/workbook_get.xml +0 -0
  301. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/graphql/__init__.py +0 -0
  302. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/graphql/paginated_object_test.py +0 -0
  303. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/__init__.py +0 -0
  304. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/auth_test.py +0 -0
  305. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/credentials_test.py +0 -0
  306. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/projects_test.py +0 -0
  307. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/usages_test.py +0 -0
  308. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/users_test.py +0 -0
  309. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/workbooks_test.py +0 -0
  310. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/utils/__init__.py +0 -0
  311. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/utils/env_key.py +0 -0
  312. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tsc_fields.py +0 -0
  313. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/types.py +0 -0
  314. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/usage.py +0 -0
  315. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/__init__.py +0 -0
  316. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/assets.py +0 -0
  317. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/__init__.py +0 -0
  318. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client.py +0 -0
  319. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client_metadata_api.py +0 -0
  320. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client_rest_api.py +0 -0
  321. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client_tsc.py +0 -0
  322. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/credentials.py +0 -0
  323. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/errors.py +0 -0
  324. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/gql_queries.py +0 -0
  325. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/rest_fields.py +0 -0
  326. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/constants.py +0 -0
  327. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/extract.py +0 -0
  328. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/__init__.py +0 -0
  329. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/__init__.py +0 -0
  330. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/credentials.py +0 -0
  331. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/endpoints.py +0 -0
  332. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/extract.py +0 -0
  333. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/__init__.py +0 -0
  334. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/__init__.py +0 -0
  335. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/asset.py +0 -0
  336. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/asset_test.py +0 -0
  337. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/extract.py +0 -0
  338. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/query.py +0 -0
  339. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
  340. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
  341. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
  342. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/client.py +0 -0
  343. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/client_test.py +0 -0
  344. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/credentials.py +0 -0
  345. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/extract.py +0 -0
  346. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
  347. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
  348. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
  349. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
  350. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
  351. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
  352. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
  353. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
  354. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
  355. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
  356. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/query.py +0 -0
  357. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/types.py +0 -0
  358. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/__init__.py +0 -0
  359. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/api_client_test.py +0 -0
  360. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/endpoints.py +0 -0
  361. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/format.py +0 -0
  362. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/format_test.py +0 -0
  363. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/pagination.py +0 -0
  364. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/utils.py +0 -0
  365. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/utils_test.py +0 -0
  366. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/__init__.py +0 -0
  367. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/client.py +0 -0
  368. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/client_test.py +0 -0
  369. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/extract.py +0 -0
  370. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/.sqlfluff +0 -0
  371. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/column.sql +0 -0
  372. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/database.sql +0 -0
  373. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/query.sql +0 -0
  374. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/schema.sql +0 -0
  375. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/table.sql +0 -0
  376. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/user.sql +0 -0
  377. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/view_ddl.sql +0 -0
  378. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/query.py +0 -0
  379. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/__init__.py +0 -0
  380. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/extract.py +0 -0
  381. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
  382. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
  383. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
  384. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
  385. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
  386. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
  387. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
  388. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/query.py +0 -0
  389. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/__init__.py +0 -0
  390. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/client.py +0 -0
  391. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/client_test.py +0 -0
  392. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/extract.py +0 -0
  393. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/extract_test.py +0 -0
  394. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
  395. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
  396. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
  397. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
  398. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
  399. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/query_serverless.sql +0 -0
  400. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
  401. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
  402. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
  403. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
  404. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -0
  405. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/query.py +0 -0
  406. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/__init__.py +0 -0
  407. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/client.py +0 -0
  408. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/constants.py +0 -0
  409. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/extract.py +0 -0
  410. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/format.py +0 -0
  411. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/format_test.py +0 -0
  412. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/pagination.py +0 -0
  413. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/soql.py +0 -0
  414. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
  415. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/client.py +0 -0
  416. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
  417. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/credentials.py +0 -0
  418. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/credentials_test.py +0 -0
  419. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/extract.py +0 -0
  420. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
  421. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/column.sql +0 -0
  422. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
  423. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
  424. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/function.sql +0 -0
  425. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
  426. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
  427. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/query.sql +0 -0
  428. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
  429. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/schema.sql +0 -0
  430. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/table.sql +0 -0
  431. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
  432. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
  433. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/query.py +0 -0
  434. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/__init__.py +0 -0
  435. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/client.py +0 -0
  436. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/extract.py +0 -0
  437. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/.sqlfluff +0 -0
  438. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/column.sql +0 -0
  439. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/database.sql +0 -0
  440. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/schema.sql +0 -0
  441. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/table.sql +0 -0
  442. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/user.sql +0 -0
  443. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/query.py +0 -0
  444. {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/synapse/queries/column.sql +0 -0
@@ -1,6 +1,22 @@
1
1
 
2
2
  # Changelog
3
3
 
4
+ ## 0.22.5 - 2025-01-09
5
+
6
+ * Databricks: validate and deduplicate lineage links
7
+
8
+ ## 0.22.4 - 2025-01-08
9
+
10
+ * ThoughtSpot: extract answers
11
+
12
+ ## 0.22.3 - 2024-12-10
13
+
14
+ * Databricks: extract lineage from system tables
15
+
16
+ ## 0.22.2 - 2024-12-06
17
+
18
+ * Sigma: multithreading to retrieve lineage
19
+
4
20
  ## 0.22.1 - 2024-12-05
5
21
 
6
22
  * Salesforce: deduplicate tables
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.22.1
3
+ Version: 0.22.5
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -207,6 +207,22 @@ For any questions or bug report, contact us at [support@castordoc.com](mailto:su
207
207
 
208
208
  # Changelog
209
209
 
210
+ ## 0.22.5 - 2025-01-09
211
+
212
+ * Databricks: validate and deduplicate lineage links
213
+
214
+ ## 0.22.4 - 2025-01-08
215
+
216
+ * ThoughtSpot: extract answers
217
+
218
+ ## 0.22.3 - 2024-12-10
219
+
220
+ * Databricks: extract lineage from system tables
221
+
222
+ ## 0.22.2 - 2024-12-06
223
+
224
+ * Sigma: multithreading to retrieve lineage
225
+
210
226
  ## 0.22.1 - 2024-12-05
211
227
 
212
228
  * Salesforce: deduplicate tables
@@ -1,9 +1,11 @@
1
1
  from collections.abc import Iterator
2
+ from concurrent.futures import ThreadPoolExecutor
2
3
  from functools import partial
3
4
  from http import HTTPStatus
4
5
  from typing import Callable, Optional
5
6
 
6
7
  import requests
8
+ from pydantic import BaseModel
7
9
 
8
10
  from ....utils import (
9
11
  APIClient,
@@ -12,6 +14,7 @@ from ....utils import (
12
14
  build_url,
13
15
  fetch_all_pages,
14
16
  handle_response,
17
+ retry,
15
18
  )
16
19
  from ..assets import SigmaAsset
17
20
  from .credentials import SigmaCredentials
@@ -29,7 +32,7 @@ _DATA_ELEMENTS: tuple[str, ...] = (
29
32
  )
30
33
 
31
34
  _AUTH_TIMEOUT_S = 60
32
- _SIGMA_TIMEOUT = 120
35
+ _SIGMA_TIMEOUT_S = 300
33
36
 
34
37
  _SIGMA_HEADERS = {
35
38
  "Content-Type": _CONTENT_TYPE,
@@ -47,6 +50,23 @@ SIGMA_SAFE_MODE = RequestSafeMode(
47
50
  max_errors=_VOLUME_IGNORED,
48
51
  status_codes=_IGNORED_ERROR_CODES,
49
52
  )
53
+ _THREADS_LINEAGE = 10 # empirically found; hit the rate limit with 20 workers
54
+ _RETRY_NUMBER = 1
55
+ _RETRY_BASE_MS = 60_000
56
+
57
+
58
+ class LineageContext(BaseModel):
59
+ """all info needed to build the endpoint for lineage retrieval"""
60
+
61
+ workbook_id: str
62
+ element_id: str
63
+
64
+
65
+ class Lineage(BaseModel):
66
+ """holds response from lineage API and context used to retrieve it"""
67
+
68
+ lineage: dict
69
+ context: LineageContext
50
70
 
51
71
 
52
72
  class SigmaBearerAuth(BearerAuth):
@@ -77,7 +97,7 @@ class SigmaClient(APIClient):
77
97
  host=credentials.host,
78
98
  auth=auth,
79
99
  headers=_SIGMA_HEADERS,
80
- timeout=_SIGMA_TIMEOUT,
100
+ timeout=_SIGMA_TIMEOUT_S,
81
101
  safe_mode=safe_mode or SIGMA_SAFE_MODE,
82
102
  )
83
103
 
@@ -133,17 +153,51 @@ class SigmaClient(APIClient):
133
153
  page=page, workbook_id=workbook_id
134
154
  )
135
155
 
136
- def _get_all_lineages(self, elements: list[dict]) -> Iterator[dict]:
156
+ @retry(
157
+ (ConnectionError,),
158
+ max_retries=_RETRY_NUMBER,
159
+ base_ms=_RETRY_BASE_MS,
160
+ log_exc_info=True,
161
+ )
162
+ def _get_lineage(self, lineage_context: LineageContext) -> Lineage:
163
+ """
164
+ return the lineage from API and other ids needed to characterize
165
+ lineage in castor
166
+ """
167
+ workbook_id = lineage_context.workbook_id
168
+ element_id = lineage_context.element_id
169
+ endpoint = SigmaEndpointFactory.lineage(workbook_id, element_id)
170
+ return Lineage(lineage=self._get(endpoint), context=lineage_context)
171
+
172
+ @staticmethod
173
+ def _lineage_context(elements: list[dict]) -> list[LineageContext]:
174
+ """
175
+ Helper function to prepare context for lineage retrieval.
176
+ Elements without associated columns are skipped.
177
+ """
178
+ contexts: list[LineageContext] = []
137
179
  for element in elements:
138
- workbook_id = element["workbook_id"]
139
- element_id = element["elementId"]
140
- lineage = self._get(
141
- endpoint=SigmaEndpointFactory.lineage(workbook_id, element_id)
180
+ if element.get("columns") is None:
181
+ continue
182
+
183
+ context = LineageContext(
184
+ workbook_id=element["workbook_id"],
185
+ element_id=element["elementId"],
142
186
  )
187
+ contexts.append(context)
188
+ return contexts
189
+
190
+ def _get_all_lineages(self, elements: list[dict]) -> Iterator[dict]:
191
+ lineage_context = self._lineage_context(elements)
192
+
193
+ with ThreadPoolExecutor(max_workers=_THREADS_LINEAGE) as executor:
194
+ results = executor.map(self._get_lineage, lineage_context)
195
+
196
+ for lineage in results:
143
197
  yield {
144
- **lineage,
145
- "workbook_id": workbook_id,
146
- "element_id": element_id,
198
+ **lineage.lineage,
199
+ "workbook_id": lineage.context.workbook_id,
200
+ "element_id": lineage.context.element_id,
147
201
  }
148
202
 
149
203
  def _get_all_queries(self, workbooks: list[dict]) -> Iterator[dict]:
@@ -4,6 +4,8 @@ from ...types import ExternalAsset
4
4
  class ThoughtspotAsset(ExternalAsset):
5
5
  """Thoughtspot assets"""
6
6
 
7
+ ANSWERS = "answers"
8
+ ANSWER_USAGES = "answer_usages"
7
9
  LIVEBOARDS = "liveboards"
10
+ LIVEBOARD_USAGES = "liveboard_usages"
8
11
  LOGICAL_TABLES = "logical_tables"
9
- USAGES = "usages"
@@ -30,7 +30,12 @@ _THOUGHTSPOT_HEADERS = {
30
30
  "Content-Type": "application/json",
31
31
  }
32
32
  _METADATA_BATCH_SIZE = 100
33
- _USAGE_LIVEBOARD_ID = "bea79810-145f-4ad0-a02c-4177a6e7d861"
33
+ # https://docs.thoughtspot.com/cloud/latest/object-usage-liveboard
34
+ _OBJECT_USAGE_LIVEBOARD = "Object Usage"
35
+ _ANSWER_USAGE_VIZ = "Answer Usage, by User"
36
+ # https://docs.thoughtspot.com/cloud/latest/user-adoption
37
+ _USER_ADOPTION_LIVEBOARD = "User Adoption"
38
+ _LIVEBOARD_USAGE_VIZ = "Popular Liveboards Last 30 Days"
34
39
  # By default, no errors are ignored for the moment
35
40
  THOUGHTSPOT_SAFE_MODE = RequestSafeMode()
36
41
 
@@ -69,23 +74,39 @@ class ThoughtspotClient(APIClient):
69
74
  def _metadata_search(
70
75
  self,
71
76
  metadata_type: str,
77
+ identifier: Optional[str] = None,
72
78
  ) -> Iterator[dict]:
79
+ """
80
+ Yields assets of the given asset type, and optionally filters on a
81
+ specific identifier.
82
+ """
73
83
  offset = 0
84
+
74
85
  while True:
86
+ search_filters = {
87
+ "metadata": [{"type": metadata_type}],
88
+ "include_details": True,
89
+ "record_size": _METADATA_BATCH_SIZE,
90
+ "record_offset": offset,
91
+ }
92
+ if identifier:
93
+ search_filters["metadata"] = {
94
+ "identifier": identifier,
95
+ "type": metadata_type,
96
+ }
97
+
75
98
  metadata = self._post(
76
99
  ThoughtspotEndpointFactory.metadata_search(),
77
- data={
78
- "metadata": [{"type": metadata_type}],
79
- "include_details": True,
80
- "record_size": _METADATA_BATCH_SIZE,
81
- "record_offset": offset,
82
- },
100
+ data=search_filters,
83
101
  )
84
102
  yield from metadata
85
103
  if len(metadata) < _METADATA_BATCH_SIZE:
86
104
  break
87
105
  offset = offset + _METADATA_BATCH_SIZE
88
106
 
107
+ def _get_all_answers(self) -> Iterator[dict]:
108
+ yield from self._metadata_search(metadata_type="ANSWER")
109
+
89
110
  def _get_all_liveboards(self) -> Iterator[dict]:
90
111
  yield from self._metadata_search(metadata_type="LIVEBOARD")
91
112
 
@@ -95,26 +116,58 @@ class ThoughtspotClient(APIClient):
95
116
  def _get_all_tables(self) -> Iterator[dict]:
96
117
  yield from self._metadata_search(metadata_type="LOGICAL_TABLE")
97
118
 
98
- def _get_liveboards_usages(self) -> Iterator[dict]:
119
+ def _get_usages(
120
+ self,
121
+ liveboard_name: str,
122
+ visualization_name: str,
123
+ ) -> Iterator[dict]:
124
+ """
125
+ Yields the data of a given visualization in the given liveboard.
126
+ ThoughtSpot maintains two system liveboards with stats about data usage,
127
+ which are useful to compute view counts and popularity.
128
+ """
129
+ usage_liveboard = next(
130
+ self._metadata_search(
131
+ metadata_type="LIVEBOARD", identifier=liveboard_name
132
+ )
133
+ )
134
+ liveboard_id = usage_liveboard["metadata_id"]
135
+
99
136
  data = self._post(
100
137
  endpoint=ThoughtspotEndpointFactory.liveboard(),
101
138
  headers={"Accept": "application/octet-stream"},
102
139
  data={
103
- "metadata_identifier": _USAGE_LIVEBOARD_ID,
140
+ "metadata_identifier": liveboard_id,
104
141
  "file_format": "CSV",
105
- "visualization_identifiers": [
106
- "Popular Liveboards Last 30 Days"
107
- ],
142
+ "visualization_identifiers": [visualization_name],
108
143
  },
109
144
  handler=lambda x: x.text,
110
145
  )
111
146
  yield from usage_liveboard_reader(data)
112
147
 
113
- def fetch(self, asset: ThoughtspotAsset):
148
+ def _get_answer_usages(self) -> Iterator[dict]:
149
+ return self._get_usages(
150
+ liveboard_name=_OBJECT_USAGE_LIVEBOARD,
151
+ visualization_name=_ANSWER_USAGE_VIZ,
152
+ )
153
+
154
+ def _get_liveboards_usages(self) -> Iterator[dict]:
155
+ return self._get_usages(
156
+ liveboard_name=_USER_ADOPTION_LIVEBOARD,
157
+ visualization_name=_LIVEBOARD_USAGE_VIZ,
158
+ )
159
+
160
+ def fetch(self, asset: ThoughtspotAsset) -> Iterator[dict]:
161
+ if asset == ThoughtspotAsset.ANSWERS:
162
+ yield from self._get_all_answers()
163
+
164
+ if asset == ThoughtspotAsset.ANSWER_USAGES:
165
+ yield from self._get_answer_usages()
166
+
114
167
  if asset == ThoughtspotAsset.LIVEBOARDS:
115
168
  yield from self._get_all_liveboards()
116
169
 
117
- if asset == ThoughtspotAsset.USAGES:
170
+ if asset == ThoughtspotAsset.LIVEBOARD_USAGES:
118
171
  yield from self._get_liveboards_usages()
119
172
 
120
173
  if asset == ThoughtspotAsset.LOGICAL_TABLES:
@@ -1,13 +1,17 @@
1
1
  import csv
2
+ import re
2
3
  from collections.abc import Iterator
3
4
  from io import StringIO
4
5
 
6
+ _END_OF_GENERATED_TEXT = r'^""$'
7
+
5
8
 
6
9
  def usage_liveboard_reader(usage_liveboard_csv: str) -> Iterator[dict]:
7
10
  """
8
11
  Converts a CSV string into an iterator of dictionaries after
9
- ignoring the first 6 lines, using the 7th line as the header.
10
- First 6 lines looks like the following:
12
+ ignoring the generated text that preceeds the actual CSV header row.
13
+ The generated block ends with a row containing only two double quotes.
14
+ Here is an example:
11
15
 
12
16
  "Data extract produced by Castor on 09/19/2024 06:54"
13
17
  "Filters applied on data :"
@@ -15,11 +19,13 @@ def usage_liveboard_reader(usage_liveboard_csv: str) -> Iterator[dict]:
15
19
  "Pinboard NOT IN [mlm - availability pinboard,null]"
16
20
  "Timestamp >= 20240820 00:00:00 < 20240919 00:00:00"
17
21
  "Timestamp >= 20240919 00:00:00 < 20240920 00:00:00"
22
+ ""
18
23
 
19
24
  """
20
25
  csv_file = StringIO(usage_liveboard_csv)
21
26
 
22
- for _ in range(7):
23
- next(csv_file)
27
+ line = next(csv_file)
28
+ while not re.match(_END_OF_GENERATED_TEXT, line.strip()):
29
+ line = next(csv_file)
24
30
 
25
31
  yield from csv.DictReader(csv_file)
@@ -2,7 +2,7 @@ from .utils import (
2
2
  usage_liveboard_reader,
3
3
  )
4
4
 
5
- VALID_CSV = '''"Data extract produced by Castor on 09/19/2024 06:54"
5
+ VALID_CSV_1 = '''"Data extract produced by Castor on 09/19/2024 06:54"
6
6
  "Filters applied on data :"
7
7
  "User Action IN [pinboard_embed_view,pinboard_tspublic_no_runtime_filter,pinboard_tspublic_runtime_filter,pinboard_view]"
8
8
  "Pinboard NOT IN [mlm - availability pinboard,null]"
@@ -16,6 +16,13 @@ VALID_CSV = '''"Data extract produced by Castor on 09/19/2024 06:54"
16
16
  "September test","25","2"'''
17
17
 
18
18
 
19
+ VALID_CSV_2 = '''"Data extract produced by Castor on 01/07/2025 16:07"
20
+ "Filters applied on data :"
21
+ "Timestamp >= 20241208 00:00:00 < 20250107 00:00:00"
22
+ ""
23
+ "Answer name","User name","Number of unique users","Count of object interactions"
24
+ "toto","tata","1","666"'''
25
+
19
26
  # Invalid CSV input (missing data rows)
20
27
  INVALID_CSV = '''"Data extract produced by Castor on 09/19/2024 06:54"
21
28
  "Filters applied on data :"
@@ -27,7 +34,7 @@ INVALID_CSV = '''"Data extract produced by Castor on 09/19/2024 06:54"
27
34
 
28
35
 
29
36
  def test_usage_liveboard_reader():
30
- expected_output = [
37
+ expected_output_1 = [
31
38
  {
32
39
  "Pinboard": "Market Report",
33
40
  "Pinboard Views": "559",
@@ -49,9 +56,20 @@ def test_usage_liveboard_reader():
49
56
  "Unique Number of User": "2",
50
57
  },
51
58
  ]
59
+ expected_output_2 = [
60
+ {
61
+ "Answer name": "toto",
62
+ "User name": "tata",
63
+ "Number of unique users": "1",
64
+ "Count of object interactions": "666",
65
+ }
66
+ ]
67
+
68
+ result = list(usage_liveboard_reader(VALID_CSV_1))
69
+ assert result == expected_output_1
52
70
 
53
- result = list(usage_liveboard_reader(VALID_CSV))
54
- assert result == expected_output
71
+ result = list(usage_liveboard_reader(VALID_CSV_2))
72
+ assert result == expected_output_2
55
73
 
56
74
  result = list(usage_liveboard_reader(INVALID_CSV))
57
75
  assert result == [] # Expect an empty result since there is no data
@@ -1,8 +1,6 @@
1
1
  import logging
2
- from collections.abc import Iterator
3
2
  from functools import partial
4
- from http import HTTPStatus
5
- from typing import Optional
3
+ from typing import Iterator, Optional
6
4
 
7
5
  import requests
8
6
 
@@ -14,16 +12,14 @@ from ...utils import (
14
12
  fetch_all_pages,
15
13
  handle_response,
16
14
  retry,
17
- retry_request,
18
15
  safe_mode,
19
16
  )
20
17
  from ..abstract import TimeFilter
21
18
  from .credentials import DatabricksCredentials
22
19
  from .endpoints import DatabricksEndpointFactory
23
20
  from .format import DatabricksFormatter, TagMapping
24
- from .lineage import single_column_lineage_links, single_table_lineage_links
25
21
  from .pagination import DATABRICKS_PAGE_SIZE, DatabricksPagination
26
- from .types import TablesColumns, TimestampedLink
22
+ from .types import TablesColumns
27
23
  from .utils import hourly_time_filters
28
24
 
29
25
  logger = logging.getLogger(__name__)
@@ -132,60 +128,6 @@ class DatabricksAPIClient(APIClient):
132
128
  column_tags=column_tags,
133
129
  )
134
130
 
135
- @safe_mode(safe_lineage_params, lambda: [])
136
- @retry(
137
- exceptions=_RETRY_EXCEPTIONS,
138
- max_retries=_RETRY_ATTEMPTS,
139
- base_ms=_RETRY_BASE_MS,
140
- )
141
- @retry_request(
142
- status_codes=(HTTPStatus.TOO_MANY_REQUESTS,),
143
- max_retries=_RETRY_ATTEMPTS,
144
- )
145
- def get_single_column_lineage(
146
- self,
147
- names: tuple[str, str],
148
- ) -> list[TimestampedLink]:
149
- """
150
- Helper function used in get_lineage_links.
151
- Call data lineage API and return the content of the result
152
-
153
- eg table_path: broward_prd.bronze.account_adjustments
154
- FYI: Maximum rate of 10 requests per SECOND
155
- """
156
- table_path, column_name = names
157
- payload = {
158
- "table_name": table_path,
159
- "column_name": column_name,
160
- "include_entity_lineage": True,
161
- }
162
- content = self._get(
163
- DatabricksEndpointFactory.column_lineage(), params=payload
164
- )
165
- column_path = f"{table_path}.{column_name}"
166
- return single_column_lineage_links(column_path, content)
167
-
168
- @safe_mode(safe_lineage_params, lambda: [])
169
- @retry(
170
- exceptions=_RETRY_EXCEPTIONS,
171
- max_retries=_RETRY_ATTEMPTS,
172
- base_ms=_RETRY_BASE_MS,
173
- )
174
- def get_single_table_lineage(
175
- self, table_path: str
176
- ) -> list[TimestampedLink]:
177
- """
178
- Helper function used in get_lineage_links.
179
- Call data lineage API and return the content of the result
180
- eg table_path: broward_prd.bronze.account_adjustments
181
- FYI: Maximum rate of 50 requests per SECOND
182
- """
183
- payload = {"table_name": table_path, "include_entity_lineage": True}
184
- content = self._get(
185
- DatabricksEndpointFactory.table_lineage(), params=payload
186
- )
187
- return single_table_lineage_links(table_path, content)
188
-
189
131
  @safe_mode(safe_query_params, lambda: [])
190
132
  @retry(
191
133
  exceptions=_RETRY_EXCEPTIONS,
@@ -1,17 +1,14 @@
1
1
  import logging
2
- from concurrent.futures import ThreadPoolExecutor
3
2
  from typing import Optional
4
3
 
5
- from ...utils import (
6
- mapping_from_rows,
7
- )
4
+ from ...utils import mapping_from_rows
8
5
  from ..abstract import TimeFilter
9
6
  from .api_client import DatabricksAPIClient
10
7
  from .credentials import DatabricksCredentials
8
+ from .enums import TagEntity
11
9
  from .format import DatabricksFormatter
12
- from .lineage import deduplicate_lineage, paths_for_column_lineage
13
- from .sql_client import DatabricksSQLClient, TagEntity
14
- from .types import TablesColumns, TimestampedLink
10
+ from .sql_client import DatabricksSQLClient
11
+ from .types import TablesColumns
15
12
 
16
13
  logger = logging.getLogger(__name__)
17
14
 
@@ -95,46 +92,6 @@ class DatabricksClient:
95
92
  columns.extend(c_to_add)
96
93
  return tables, columns
97
94
 
98
- def table_lineage(self, tables: list[dict]) -> list[dict]:
99
- """
100
- Wrapper function that retrieves all table lineage
101
- """
102
- # retrieve table lineage
103
- with ThreadPoolExecutor(max_workers=_THREADS_TABLE_LINEAGE) as executor:
104
- table_paths = [
105
- ".".join([table["schema_id"], table["table_name"]])
106
- for table in tables
107
- ]
108
- results = executor.map(
109
- self.api_client.get_single_table_lineage, table_paths
110
- )
111
- lineages = [link for links in results for link in links]
112
- deduplicated = deduplicate_lineage(lineages)
113
- return self.formatter.format_lineage(deduplicated)
114
-
115
- def column_lineage(
116
- self, tables: list[dict], columns: list[dict], table_lineage: list[dict]
117
- ) -> list[dict]:
118
- """
119
- Wrapper function that retrieves all column lineage
120
- we only try to retrieve column lineage if we found table lineage
121
- """
122
- candidate_paths = paths_for_column_lineage(
123
- tables, columns, table_lineage
124
- )
125
- # retrieve column lineage
126
- with ThreadPoolExecutor(
127
- max_workers=_THREADS_COLUMN_LINEAGE
128
- ) as executor:
129
- results = executor.map(
130
- self.api_client.get_single_column_lineage, candidate_paths
131
- )
132
- lineages: list[TimestampedLink] = [
133
- link for links in results for link in links
134
- ]
135
- deduplicated = deduplicate_lineage(lineages)
136
- return self.formatter.format_lineage(deduplicated)
137
-
138
95
  def queries(self, time_filter: Optional[TimeFilter] = None) -> list[dict]:
139
96
  return self.api_client.queries(time_filter)
140
97
 
@@ -1,14 +1,4 @@
1
- from unittest.mock import Mock, patch
2
-
3
- from .client import (
4
- DatabricksClient,
5
- )
6
- from .test_constants import (
7
- CLOSER_DATE,
8
- MOCK_TABLES_FOR_TABLE_LINEAGE,
9
- OLDER_DATE,
10
- TABLE_LINEAGE_SIDE_EFFECT,
11
- )
1
+ from .client import DatabricksClient
12
2
 
13
3
 
14
4
  class MockDatabricksClient(DatabricksClient):
@@ -48,27 +38,3 @@ def test_DatabricksClient__match_table_with_user():
48
38
  table_without_owner = {"id": 1, "owner_email": None}
49
39
  actual = client._match_table_with_user(table_without_owner, user_mapping)
50
40
  assert actual == table_without_owner
51
-
52
-
53
- @patch(
54
- "source.packages.extractor.castor_extractor.warehouse.databricks.client.DatabricksAPIClient._get",
55
- side_effect=TABLE_LINEAGE_SIDE_EFFECT,
56
- )
57
- def test_DatabricksClient_table_lineage(mock_get):
58
- client = DatabricksClient(Mock())
59
-
60
- lineage = client.table_lineage(MOCK_TABLES_FOR_TABLE_LINEAGE)
61
- assert len(lineage) == 2
62
-
63
- expected_link_1 = {
64
- "parent_path": "dev.silver.pre_analytics",
65
- "child_path": "dev.silver.analytics",
66
- "timestamp": OLDER_DATE,
67
- }
68
- expected_link_2 = {
69
- "parent_path": "dev.bronze.analytics",
70
- "child_path": "dev.silver.analytics",
71
- "timestamp": CLOSER_DATE,
72
- }
73
- assert expected_link_1 in lineage
74
- assert expected_link_2 in lineage
@@ -1,24 +1,22 @@
1
1
  from dataclasses import field
2
- from typing import Optional
3
2
 
4
- from pydantic.dataclasses import dataclass
5
- from pydantic_settings import SettingsConfigDict
3
+ from pydantic_settings import BaseSettings, SettingsConfigDict
6
4
 
7
5
  DATABRICKS_ENV_PREFIX = "CASTOR_DATABRICKS_"
8
6
 
9
7
 
10
- @dataclass
11
- class DatabricksCredentials:
8
+ class DatabricksCredentials(BaseSettings):
12
9
  """
13
10
  Credentials needed by Databricks client
14
11
  Requires:
15
12
  - host
13
+ - http_path
16
14
  - token
17
15
  """
18
16
 
19
17
  host: str
18
+ http_path: str
20
19
  token: str = field(metadata={"sensitive": True})
21
- http_path: Optional[str] = field(default=None)
22
20
 
23
21
  model_config = SettingsConfigDict(
24
22
  env_prefix=DATABRICKS_ENV_PREFIX,
@@ -0,0 +1,15 @@
1
+ from enum import Enum
2
+
3
+
4
+ class LineageEntity(Enum):
5
+ """Entities that can be linked in Databricks lineage"""
6
+
7
+ COLUMN = "COLUMN"
8
+ TABLE = "TABLE"
9
+
10
+
11
+ class TagEntity(Enum):
12
+ """Entities that can be tagged in Databricks"""
13
+
14
+ COLUMN = "COLUMN"
15
+ TABLE = "TABLE"