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.
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/CHANGELOG.md +16 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/PKG-INFO +17 -1
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/client.py +64 -10
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/assets.py +3 -1
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/client.py +67 -14
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/utils.py +10 -4
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/utils_test.py +22 -4
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/api_client.py +2 -60
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/client.py +4 -47
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/client_test.py +1 -35
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/credentials.py +4 -6
- castor_extractor-0.22.5/castor_extractor/warehouse/databricks/enums.py +15 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/extract.py +13 -11
- castor_extractor-0.22.5/castor_extractor/warehouse/databricks/lineage.py +69 -0
- castor_extractor-0.22.5/castor_extractor/warehouse/databricks/lineage_test.py +89 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/sql_client.py +23 -8
- castor_extractor-0.22.5/castor_extractor/warehouse/databricks/types.py +1 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/pyproject.toml +1 -1
- castor_extractor-0.22.1/castor_extractor/warehouse/databricks/lineage.py +0 -141
- castor_extractor-0.22.1/castor_extractor/warehouse/databricks/lineage_test.py +0 -34
- castor_extractor-0.22.1/castor_extractor/warehouse/databricks/test_constants.py +0 -79
- castor_extractor-0.22.1/castor_extractor/warehouse/databricks/types.py +0 -8
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/Dockerfile +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/DockerfileUsage.md +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/LICENCE +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/README.md +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_bigquery.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_confluence.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_databricks.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_domo.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_looker.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_metabase_api.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_metabase_db.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_mode.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_mysql.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_notion.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_postgres.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_powerbi.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_qlik.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_redshift.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_salesforce.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_salesforce_reporting.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_sigma.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_snowflake.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_sqlserver.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_tableau.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/extract_thoughtspot.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/file_check.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/commands/upload.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/column.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/column_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/enums.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file_test_users.csv +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/templates/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/confluence/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/knowledge/notion/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/logger.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/quality/soda/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/types.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/constant.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/env.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/env_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/settings.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/upload.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/upload_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/uploader/utils.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/argument_parser.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/argument_parser_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/abstract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/auth.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/auth_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/pagination_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/safe_request.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/safe_request_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/utils.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/api/utils_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/postgres.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/uri.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/client/uri_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/collection.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/collection_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/dbt/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/deprecate.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/env.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/files.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/files_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter_test.csv +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter_test.json +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/formatter_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/json_stream_write.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/load.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/object.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/object_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager_on_id.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager_on_id_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/pager/pager_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/retry.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/retry_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/safe.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/safe_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/credentials_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/salesforce/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/store.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/string.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/string_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/time.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/time_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/type.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/validation.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/validation_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/utils/write.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/client/pagination_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/domo/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/extraction_parameters.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/sdk.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/api/utils.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/constant.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/fields.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/fields_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker/multithreading.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/enums.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/looker_studio/client/scopes.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/client/shared.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/errors.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/metabase/types.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/client_test.json +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/errors.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/mode/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/authentication.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/powerbi/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/master.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/rest.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/qlik/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/client/rest.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/client/soql.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/salesforce_reporting/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/sigma/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/client_utils.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/project.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/client/safe_mode.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/errors.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/gql_fields.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/__init__.py +0 -0
- {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
- {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
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/auth.xml +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/project_get.xml +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/user_get.xml +0 -0
- {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
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/assets/rest_api/workbook_get.xml +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/graphql/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/graphql/paginated_object_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/auth_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/credentials_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/projects_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/usages_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/users_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/rest_api/workbooks_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/utils/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tests/unit/utils/env_key.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/tsc_fields.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/types.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau/usage.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/assets.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client_metadata_api.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client_rest_api.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/client_tsc.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/errors.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/gql_queries.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/client/rest_fields.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/tableau_revamp/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/client/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/visualization/thoughtspot/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/asset.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/asset_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/bigquery/types.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/api_client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/endpoints.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/format.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/format_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/utils.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/utils_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/column.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/query.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/schema.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/queries/view_ddl.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/mysql/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/postgres/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/extract_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/query_serverless.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/redshift/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/constants.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/format.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/format_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/pagination.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/salesforce/soql.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/credentials.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/credentials_test.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/column.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/function.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/query.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/schema.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/snowflake/query.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/__init__.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/client.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/extract.py +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/.sqlfluff +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/column.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/database.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/schema.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/table.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/queries/user.sql +0 -0
- {castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/sqlserver/query.py +0 -0
- {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.
|
|
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
|
-
|
|
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=
|
|
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
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|
|
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":
|
|
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
|
|
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.
|
|
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
|
|
10
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
54
|
-
assert result ==
|
|
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
|
|
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
|
|
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,
|
{castor_extractor-0.22.1 → castor_extractor-0.22.5}/castor_extractor/warehouse/databricks/client.py
RENAMED
|
@@ -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 .
|
|
13
|
-
from .
|
|
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
|
|
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
|
|
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
|
-
|
|
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"
|