castor-extractor 0.24.1__tar.gz → 0.24.4__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.24.1 → castor_extractor-0.24.4}/CHANGELOG.md +16 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/PKG-INFO +17 -1
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_tableau.py +2 -2
- castor_extractor-0.24.4/castor_extractor/visualization/tableau/__init__.py +3 -0
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/assets.py +4 -4
- castor_extractor-0.24.4/castor_extractor/visualization/tableau/client/__init__.py +2 -0
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/client.py +15 -15
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/client_metadata_api.py +9 -9
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/client_rest_api.py +6 -6
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/client_tsc.py +9 -9
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/credentials.py +2 -2
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/gql_queries.py +8 -8
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/rest_fields.py +10 -10
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/extract.py +7 -7
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/client/client.py +54 -17
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/client/endpoints.py +2 -2
- castor_extractor-0.24.4/castor_extractor/visualization/thoughtspot/client/pagination.py +25 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/column.sql +3 -1
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/query.sql +19 -11
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/schema.sql +1 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/table.sql +2 -2
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/pyproject.toml +1 -1
- castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp/__init__.py +0 -3
- castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp/client/__init__.py +0 -2
- castor_extractor-0.24.1/castor_extractor/visualization/thoughtspot/client/utils.py +0 -31
- castor_extractor-0.24.1/castor_extractor/visualization/thoughtspot/client/utils_test.py +0 -75
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/Dockerfile +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/DockerfileUsage.md +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/LICENCE +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/README.md +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_bigquery.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_confluence.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_databricks.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_domo.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_looker.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_looker_studio.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_metabase_api.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_metabase_db.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_mode.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_mysql.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_notion.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_postgres.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_powerbi.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_qlik.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_redshift.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_salesforce.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_salesforce_reporting.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_sigma.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_snowflake.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_sqlserver.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_thoughtspot.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/file_check.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/upload.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/column.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/column_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/enums.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/file.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/file_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/file_test_users.csv +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/templates/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/confluence/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/knowledge/notion/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/logger.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/quality/soda/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/types.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/constant.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/env.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/env_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/settings.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/upload.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/upload_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/uploader/utils.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/argument_parser.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/argument_parser_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/abstract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/auth.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/auth_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/pagination_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/safe_request.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/safe_request_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/utils.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/api/utils_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/postgres.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/uri.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/client/uri_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/collection.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/collection_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/dbt/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/dbt/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/dbt/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/dbt/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/dbt/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/deprecate.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/env.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/files.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/files_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/formatter.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/formatter_test.csv +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/formatter_test.json +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/formatter_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/json_stream_write.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/load.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/object.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/object_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/pager/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/pager/pager.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/pager/pager_on_id.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/pager/pager_on_id_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/pager/pager_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/retry.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/retry_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/safe.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/safe_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/credentials_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/salesforce/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/store.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/string.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/string_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/time.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/time_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/type.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/validation.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/validation_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/utils/write.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/client/pagination_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/domo/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/extraction_parameters.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/sdk.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/api/utils.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/constant.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/fields.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/fields_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker/multithreading.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/enums.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/queries/query.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/client/scopes.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/looker_studio/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/api/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/client/shared.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/errors.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/metabase/types.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/client/client_test.json +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/client/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/client/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/errors.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/mode/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/authentication.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/powerbi/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/master.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/rest.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/qlik/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/salesforce_reporting/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/salesforce_reporting/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/salesforce_reporting/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/salesforce_reporting/client/rest.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/salesforce_reporting/client/soql.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/salesforce_reporting/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/client/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/sigma/extract.py +0 -0
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/client/errors.py +0 -0
- {castor_extractor-0.24.1/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.4/castor_extractor/visualization/tableau}/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/assets.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/client/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/client/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/visualization/thoughtspot/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/asset.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/asset_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/bigquery/types.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/api_client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/api_client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/endpoints.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/enums.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/format.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/format_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/lineage.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/lineage_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/sql_client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/types.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/utils.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/databricks/utils_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/column.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/query.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/schema.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/table.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/mysql/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/postgres/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/extract_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/query_serverless.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/redshift/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/constants.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/format.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/format_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/pagination.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/salesforce/soql.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/credentials.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/credentials_test.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/function.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/snowflake/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/__init__.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/client.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/extract.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/queries/column.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/queries/database.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/queries/schema.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/queries/table.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/queries/user.sql +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/sqlserver/query.py +0 -0
- {castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/warehouse/synapse/queries/column.sql +0 -0
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.24.4 - 2025-03-19
|
|
4
|
+
|
|
5
|
+
* Snowflake:
|
|
6
|
+
* improve the list of ignored queries in the query history extraction
|
|
7
|
+
* ignore the following query types : CALL, COMMENT, EXPLAIN, REFRESH_DYNAMIC_TABLE_AT_REFRESH_VERSION, REVOKE, TRUNCATE_TABLE, UNDROP
|
|
8
|
+
* ignore queries with empty text
|
|
9
|
+
* filter out schemas with empty names
|
|
10
|
+
|
|
11
|
+
## 0.24.3 - 2025-03-18
|
|
12
|
+
|
|
13
|
+
* Replace ThoughtSpot endpoint `/api/rest/2.0/report/liveboard` with `/api/rest/2.0/metadata/liveboard/data` following the deprecation of the CSV option
|
|
14
|
+
|
|
15
|
+
## 0.24.2 - 2025-03-17
|
|
16
|
+
|
|
17
|
+
* Rename Revamped Tableau Connector classes
|
|
18
|
+
|
|
3
19
|
## 0.24.1 - 2025-03-14
|
|
4
20
|
|
|
5
21
|
* Added support for Looker Studio
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: castor-extractor
|
|
3
|
-
Version: 0.24.
|
|
3
|
+
Version: 0.24.4
|
|
4
4
|
Summary: Extract your metadata assets.
|
|
5
5
|
Home-page: https://www.castordoc.com/
|
|
6
6
|
License: EULA
|
|
@@ -210,6 +210,22 @@ For any questions or bug report, contact us at [support@castordoc.com](mailto:su
|
|
|
210
210
|
|
|
211
211
|
# Changelog
|
|
212
212
|
|
|
213
|
+
## 0.24.4 - 2025-03-19
|
|
214
|
+
|
|
215
|
+
* Snowflake:
|
|
216
|
+
* improve the list of ignored queries in the query history extraction
|
|
217
|
+
* ignore the following query types : CALL, COMMENT, EXPLAIN, REFRESH_DYNAMIC_TABLE_AT_REFRESH_VERSION, REVOKE, TRUNCATE_TABLE, UNDROP
|
|
218
|
+
* ignore queries with empty text
|
|
219
|
+
* filter out schemas with empty names
|
|
220
|
+
|
|
221
|
+
## 0.24.3 - 2025-03-18
|
|
222
|
+
|
|
223
|
+
* Replace ThoughtSpot endpoint `/api/rest/2.0/report/liveboard` with `/api/rest/2.0/metadata/liveboard/data` following the deprecation of the CSV option
|
|
224
|
+
|
|
225
|
+
## 0.24.2 - 2025-03-17
|
|
226
|
+
|
|
227
|
+
* Rename Revamped Tableau Connector classes
|
|
228
|
+
|
|
213
229
|
## 0.24.1 - 2025-03-14
|
|
214
230
|
|
|
215
231
|
* Added support for Looker Studio
|
{castor_extractor-0.24.1 → castor_extractor-0.24.4}/castor_extractor/commands/extract_tableau.py
RENAMED
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
from argparse import ArgumentParser
|
|
3
3
|
|
|
4
4
|
from castor_extractor.utils import parse_filled_arguments # type: ignore
|
|
5
|
-
from castor_extractor.visualization import
|
|
5
|
+
from castor_extractor.visualization import tableau # type: ignore
|
|
6
6
|
|
|
7
7
|
logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")
|
|
8
8
|
|
|
@@ -36,4 +36,4 @@ def main():
|
|
|
36
36
|
|
|
37
37
|
parser.add_argument("-o", "--output", help="Directory to write to")
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
tableau.extract_all(**parse_filled_arguments(parser))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from ...types import ExternalAsset
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class TableauAsset(ExternalAsset):
|
|
5
5
|
"""
|
|
6
6
|
Tableau assets
|
|
7
7
|
"""
|
|
@@ -23,7 +23,7 @@ class TableauRevampAsset(ExternalAsset):
|
|
|
23
23
|
|
|
24
24
|
# assets that are only available for clients using Tableau Pulse
|
|
25
25
|
TABLEAU_PULSE_ASSETS = (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
TableauAsset.METRIC,
|
|
27
|
+
TableauAsset.METRIC_DEFINITION,
|
|
28
|
+
TableauAsset.SUBSCRIPTION,
|
|
29
29
|
)
|
|
@@ -4,31 +4,31 @@ from typing import Optional
|
|
|
4
4
|
import tableauserverclient as TSC # type: ignore
|
|
5
5
|
|
|
6
6
|
from ....utils import SerializedAsset
|
|
7
|
-
from ..assets import TABLEAU_PULSE_ASSETS,
|
|
7
|
+
from ..assets import TABLEAU_PULSE_ASSETS, TableauAsset
|
|
8
8
|
from ..constants import CREDENTIALS_SITE_ID_KEY, DEFAULT_TIMEOUT_SECONDS
|
|
9
9
|
from .client_metadata_api import TableauClientMetadataApi
|
|
10
10
|
from .client_rest_api import TableauClientRestApi
|
|
11
11
|
from .client_tsc import TableauClientTSC
|
|
12
|
-
from .credentials import
|
|
12
|
+
from .credentials import TableauCredentials
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
16
|
# these assets must be extracted via TableauServerClient (TSC)
|
|
17
17
|
_TSC_ASSETS = (
|
|
18
18
|
# projects are not available in Metadata API
|
|
19
|
-
|
|
19
|
+
TableauAsset.PROJECT,
|
|
20
20
|
# view count are not available in Metadata API
|
|
21
|
-
|
|
21
|
+
TableauAsset.USAGE,
|
|
22
22
|
# only users who published content can be extracted from MetadataAPI
|
|
23
|
-
|
|
23
|
+
TableauAsset.USER,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
# these assets must be extracted via the REST API
|
|
27
27
|
_REST_API_ASSETS = (
|
|
28
28
|
# Tableau Pulse assets are only available in REST API
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
TableauAsset.METRIC,
|
|
30
|
+
TableauAsset.METRIC_DEFINITION,
|
|
31
|
+
TableauAsset.SUBSCRIPTION,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
logging.getLogger("tableau.endpoint").setLevel(logging.WARNING)
|
|
@@ -109,7 +109,7 @@ def _server(
|
|
|
109
109
|
return server
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
class
|
|
112
|
+
class TableauClient:
|
|
113
113
|
"""
|
|
114
114
|
Connect to Tableau's API and extract assets.
|
|
115
115
|
|
|
@@ -119,7 +119,7 @@ class TableauRevampClient:
|
|
|
119
119
|
|
|
120
120
|
def __init__(
|
|
121
121
|
self,
|
|
122
|
-
credentials:
|
|
122
|
+
credentials: TableauCredentials,
|
|
123
123
|
timeout_sec: int = DEFAULT_TIMEOUT_SECONDS,
|
|
124
124
|
with_pulse: bool = False,
|
|
125
125
|
override_page_size: Optional[int] = None,
|
|
@@ -186,7 +186,7 @@ class TableauRevampClient:
|
|
|
186
186
|
)
|
|
187
187
|
|
|
188
188
|
def _fetch_datasources(self) -> SerializedAsset:
|
|
189
|
-
asset =
|
|
189
|
+
asset = TableauAsset.DATASOURCE
|
|
190
190
|
|
|
191
191
|
datasources = self._client_metadata.fetch(asset)
|
|
192
192
|
tsc_datasources = self._client_tsc.fetch(asset)
|
|
@@ -194,7 +194,7 @@ class TableauRevampClient:
|
|
|
194
194
|
return _merge_datasources(datasources, tsc_datasources)
|
|
195
195
|
|
|
196
196
|
def _fetch_workbooks(self) -> SerializedAsset:
|
|
197
|
-
asset =
|
|
197
|
+
asset = TableauAsset.WORKBOOK
|
|
198
198
|
|
|
199
199
|
site_id = self._credentials.site_id
|
|
200
200
|
workbooks = self._client_metadata.fetch(asset)
|
|
@@ -206,7 +206,7 @@ class TableauRevampClient:
|
|
|
206
206
|
|
|
207
207
|
def fetch(
|
|
208
208
|
self,
|
|
209
|
-
asset:
|
|
209
|
+
asset: TableauAsset,
|
|
210
210
|
) -> SerializedAsset:
|
|
211
211
|
"""
|
|
212
212
|
Extract the given Tableau Asset
|
|
@@ -217,11 +217,11 @@ class TableauRevampClient:
|
|
|
217
217
|
|
|
218
218
|
logger.info(f"Extracting {asset.name}...")
|
|
219
219
|
|
|
220
|
-
if asset ==
|
|
220
|
+
if asset == TableauAsset.DATASOURCE:
|
|
221
221
|
# two APIs are required to extract datasources
|
|
222
222
|
return self._fetch_datasources()
|
|
223
223
|
|
|
224
|
-
if asset ==
|
|
224
|
+
if asset == TableauAsset.WORKBOOK:
|
|
225
225
|
# two APIs are required to extract workbooks
|
|
226
226
|
return self._fetch_workbooks()
|
|
227
227
|
|
|
@@ -4,21 +4,21 @@ from typing import Optional
|
|
|
4
4
|
import tableauserverclient as TSC # type: ignore
|
|
5
5
|
|
|
6
6
|
from ....utils import SerializedAsset, retry
|
|
7
|
-
from ..assets import
|
|
7
|
+
from ..assets import TableauAsset
|
|
8
8
|
from ..constants import DEFAULT_PAGE_SIZE
|
|
9
9
|
from .errors import TableauApiError, TableauApiTimeout
|
|
10
10
|
from .gql_queries import FIELDS_QUERIES, GQL_QUERIES, QUERY_TEMPLATE
|
|
11
11
|
|
|
12
12
|
# increase the value when extraction is too slow
|
|
13
13
|
# decrease the value when timeouts arise
|
|
14
|
-
_CUSTOM_PAGE_SIZE: dict[
|
|
14
|
+
_CUSTOM_PAGE_SIZE: dict[TableauAsset, int] = {
|
|
15
15
|
# for some clients, extraction of columns tend to hit the node limit
|
|
16
16
|
# https://community.tableau.com/s/question/0D54T00000YuK60SAF/metadata-query-nodelimitexceeded-error
|
|
17
17
|
# the workaround is to reduce pagination
|
|
18
|
-
|
|
18
|
+
TableauAsset.COLUMN: 50,
|
|
19
19
|
# fields are light but volumes are bigger
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
TableauAsset.FIELD: 1000,
|
|
21
|
+
TableauAsset.TABLE: 50,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
_TIMEOUT_MESSAGE = (
|
|
@@ -115,7 +115,7 @@ class TableauClientMetadataApi:
|
|
|
115
115
|
result_pages = gql_query_scroll(self._server, query, resource)
|
|
116
116
|
return [asset for page in result_pages for asset in page]
|
|
117
117
|
|
|
118
|
-
def _page_size(self, asset:
|
|
118
|
+
def _page_size(self, asset: TableauAsset) -> int:
|
|
119
119
|
return (
|
|
120
120
|
self._override_page_size
|
|
121
121
|
or _CUSTOM_PAGE_SIZE.get(asset)
|
|
@@ -124,7 +124,7 @@ class TableauClientMetadataApi:
|
|
|
124
124
|
|
|
125
125
|
def _fetch_fields(self) -> SerializedAsset:
|
|
126
126
|
result: SerializedAsset = []
|
|
127
|
-
page_size = self._page_size(
|
|
127
|
+
page_size = self._page_size(TableauAsset.FIELD)
|
|
128
128
|
for resource, fields in FIELDS_QUERIES:
|
|
129
129
|
current = self._call(resource, fields, page_size)
|
|
130
130
|
result.extend(current)
|
|
@@ -132,9 +132,9 @@ class TableauClientMetadataApi:
|
|
|
132
132
|
|
|
133
133
|
def fetch(
|
|
134
134
|
self,
|
|
135
|
-
asset:
|
|
135
|
+
asset: TableauAsset,
|
|
136
136
|
) -> SerializedAsset:
|
|
137
|
-
if asset ==
|
|
137
|
+
if asset == TableauAsset.FIELD:
|
|
138
138
|
return self._fetch_fields()
|
|
139
139
|
|
|
140
140
|
page_size = self._page_size(asset)
|
|
@@ -5,7 +5,7 @@ import requests
|
|
|
5
5
|
import tableauserverclient as TSC # type: ignore
|
|
6
6
|
|
|
7
7
|
from ....utils import SerializedAsset, deduplicate
|
|
8
|
-
from ..assets import
|
|
8
|
+
from ..assets import TableauAsset
|
|
9
9
|
from .rest_fields import REST_FIELDS
|
|
10
10
|
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
@@ -17,7 +17,7 @@ _METRICS_DEFINITION_URL = "{base}/pulse/site/{site}/{definition_id}"
|
|
|
17
17
|
|
|
18
18
|
def _pick(
|
|
19
19
|
data: SerializedAsset,
|
|
20
|
-
asset:
|
|
20
|
+
asset: TableauAsset,
|
|
21
21
|
) -> SerializedAsset:
|
|
22
22
|
keys = REST_FIELDS[asset]
|
|
23
23
|
return [{key: row[key] for key in keys} for row in data]
|
|
@@ -107,18 +107,18 @@ class TableauClientRestApi:
|
|
|
107
107
|
|
|
108
108
|
def fetch(
|
|
109
109
|
self,
|
|
110
|
-
asset:
|
|
110
|
+
asset: TableauAsset,
|
|
111
111
|
) -> SerializedAsset:
|
|
112
|
-
if asset ==
|
|
112
|
+
if asset == TableauAsset.SUBSCRIPTION:
|
|
113
113
|
# https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_pulse.htm#PulseSubscriptionService_ListSubscriptions
|
|
114
114
|
data = self._call(path=_PULSE_API, target="subscriptions")
|
|
115
115
|
|
|
116
|
-
elif asset ==
|
|
116
|
+
elif asset == TableauAsset.METRIC_DEFINITION:
|
|
117
117
|
# https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_pulse.htm#MetricQueryService_ListDefinitions
|
|
118
118
|
data = self._call(path=_PULSE_API, target="definitions")
|
|
119
119
|
self._compute_metric_url(data)
|
|
120
120
|
|
|
121
|
-
elif asset ==
|
|
121
|
+
elif asset == TableauAsset.METRIC:
|
|
122
122
|
# https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_pulse.htm#MetricQueryService_ListMetrics
|
|
123
123
|
definitions = self._call(path=_PULSE_API, target="definitions")
|
|
124
124
|
data = self._fetch_metrics(definitions)
|
|
@@ -4,7 +4,7 @@ from typing import Any
|
|
|
4
4
|
import tableauserverclient as TSC # type: ignore
|
|
5
5
|
|
|
6
6
|
from ....utils import JsonType, SerializedAsset
|
|
7
|
-
from ..assets import
|
|
7
|
+
from ..assets import TableauAsset
|
|
8
8
|
from .rest_fields import REST_FIELDS
|
|
9
9
|
|
|
10
10
|
|
|
@@ -30,13 +30,13 @@ class TableauClientTSC:
|
|
|
30
30
|
def _pick_fields(
|
|
31
31
|
self,
|
|
32
32
|
data: Iterable,
|
|
33
|
-
asset:
|
|
33
|
+
asset: TableauAsset,
|
|
34
34
|
) -> Iterator[dict]:
|
|
35
35
|
keys = REST_FIELDS[asset]
|
|
36
36
|
|
|
37
37
|
for row in data:
|
|
38
38
|
fields = {key: _pick(row, key) for key in keys}
|
|
39
|
-
if asset ==
|
|
39
|
+
if asset == TableauAsset.USER:
|
|
40
40
|
self._server.users.populate_groups(row)
|
|
41
41
|
fields["group_ids"] = [group.id for group in row.groups]
|
|
42
42
|
|
|
@@ -44,21 +44,21 @@ class TableauClientTSC:
|
|
|
44
44
|
|
|
45
45
|
def fetch(
|
|
46
46
|
self,
|
|
47
|
-
asset:
|
|
47
|
+
asset: TableauAsset,
|
|
48
48
|
) -> SerializedAsset:
|
|
49
|
-
if asset ==
|
|
49
|
+
if asset == TableauAsset.DATASOURCE:
|
|
50
50
|
data = TSC.Pager(self._server.datasources)
|
|
51
51
|
|
|
52
|
-
elif asset ==
|
|
52
|
+
elif asset == TableauAsset.PROJECT:
|
|
53
53
|
data = TSC.Pager(self._server.projects)
|
|
54
54
|
|
|
55
|
-
elif asset ==
|
|
55
|
+
elif asset == TableauAsset.USAGE:
|
|
56
56
|
data = TSC.Pager(self._server.views, usage=True)
|
|
57
57
|
|
|
58
|
-
elif asset ==
|
|
58
|
+
elif asset == TableauAsset.USER:
|
|
59
59
|
data = TSC.Pager(self._server.users)
|
|
60
60
|
|
|
61
|
-
elif asset ==
|
|
61
|
+
elif asset == TableauAsset.WORKBOOK:
|
|
62
62
|
data = TSC.Pager(self._server.workbooks)
|
|
63
63
|
|
|
64
64
|
else:
|
|
@@ -15,7 +15,7 @@ _DEFAULT_SITE_ID_USER_INPUT = "default"
|
|
|
15
15
|
TABLEAU_ENV_PREFIX = "CASTOR_TABLEAU_"
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class
|
|
18
|
+
class TableauCredentials(BaseSettings):
|
|
19
19
|
"""
|
|
20
20
|
Tableau's credentials to connect to both APIs (REST and GRAPHQL)
|
|
21
21
|
"""
|
|
@@ -42,7 +42,7 @@ class TableauRevampCredentials(BaseSettings):
|
|
|
42
42
|
return site_id
|
|
43
43
|
|
|
44
44
|
@model_validator(mode="after")
|
|
45
|
-
def _check_user_xor_pat_login(self) -> "
|
|
45
|
+
def _check_user_xor_pat_login(self) -> "TableauCredentials":
|
|
46
46
|
"""
|
|
47
47
|
Checks that credentials are correctly input, it means either:
|
|
48
48
|
- User and password are filled
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from ..assets import
|
|
1
|
+
from ..assets import TableauAsset
|
|
2
2
|
|
|
3
3
|
QUERY_TEMPLATE = """
|
|
4
4
|
{{
|
|
@@ -128,13 +128,13 @@ workbook { id }
|
|
|
128
128
|
"""
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
GQL_QUERIES: dict[
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
GQL_QUERIES: dict[TableauAsset, tuple[str, str]] = {
|
|
132
|
+
TableauAsset.COLUMN: ("columns", _COLUMNS_QUERY),
|
|
133
|
+
TableauAsset.DASHBOARD: ("dashboards", _DASHBOARDS_QUERY),
|
|
134
|
+
TableauAsset.DATASOURCE: ("datasources", _DATASOURCES_QUERY),
|
|
135
|
+
TableauAsset.SHEET: ("sheets", _SHEETS_QUERY),
|
|
136
|
+
TableauAsset.TABLE: ("tables", _TABLES_QUERY),
|
|
137
|
+
TableauAsset.WORKBOOK: ("workbooks", _WORKBOOKS_QUERY),
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
FIELDS_QUERIES = (
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
from ..assets import
|
|
1
|
+
from ..assets import TableauAsset
|
|
2
2
|
|
|
3
3
|
# list of fields to pick in REST API or TSC responses
|
|
4
|
-
REST_FIELDS: dict[
|
|
5
|
-
|
|
4
|
+
REST_FIELDS: dict[TableauAsset, set[str]] = {
|
|
5
|
+
TableauAsset.DATASOURCE: {
|
|
6
6
|
"id",
|
|
7
7
|
"project_id",
|
|
8
8
|
"webpage_url",
|
|
9
9
|
},
|
|
10
|
-
|
|
10
|
+
TableauAsset.METRIC: {
|
|
11
11
|
"id",
|
|
12
12
|
"definition_id",
|
|
13
13
|
},
|
|
14
|
-
|
|
14
|
+
TableauAsset.METRIC_DEFINITION: {
|
|
15
15
|
"metadata",
|
|
16
16
|
"specification",
|
|
17
17
|
},
|
|
18
|
-
|
|
18
|
+
TableauAsset.PROJECT: {
|
|
19
19
|
"description",
|
|
20
20
|
"id",
|
|
21
21
|
"name",
|
|
22
22
|
"parent_id",
|
|
23
23
|
},
|
|
24
|
-
|
|
24
|
+
TableauAsset.SUBSCRIPTION: {
|
|
25
25
|
"follower",
|
|
26
26
|
"id",
|
|
27
27
|
"metric_id",
|
|
28
28
|
},
|
|
29
|
-
|
|
29
|
+
TableauAsset.USAGE: {
|
|
30
30
|
"name",
|
|
31
31
|
"total_views",
|
|
32
32
|
"workbook_id",
|
|
33
33
|
},
|
|
34
|
-
|
|
34
|
+
TableauAsset.USER: {
|
|
35
35
|
"email",
|
|
36
36
|
"fullname",
|
|
37
37
|
"id",
|
|
38
38
|
"name",
|
|
39
39
|
"site_role",
|
|
40
40
|
},
|
|
41
|
-
|
|
41
|
+
TableauAsset.WORKBOOK: {
|
|
42
42
|
"id",
|
|
43
43
|
"project_id",
|
|
44
44
|
},
|
|
@@ -10,18 +10,18 @@ from ...utils import (
|
|
|
10
10
|
write_json,
|
|
11
11
|
write_summary,
|
|
12
12
|
)
|
|
13
|
-
from .assets import
|
|
14
|
-
from .client import
|
|
13
|
+
from .assets import TableauAsset
|
|
14
|
+
from .client import TableauClient, TableauCredentials
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def iterate_all_data(
|
|
20
|
-
client:
|
|
21
|
-
) -> Iterable[tuple[
|
|
20
|
+
client: TableauClient,
|
|
21
|
+
) -> Iterable[tuple[TableauAsset, list]]:
|
|
22
22
|
"""Iterate over the extracted Data from Tableau"""
|
|
23
23
|
|
|
24
|
-
for asset in
|
|
24
|
+
for asset in TableauAsset:
|
|
25
25
|
data = client.fetch(asset)
|
|
26
26
|
yield asset, deep_serialize(data)
|
|
27
27
|
|
|
@@ -36,8 +36,8 @@ def extract_all(**kwargs) -> None:
|
|
|
36
36
|
page_size = kwargs.get("page_size")
|
|
37
37
|
timestamp = current_timestamp()
|
|
38
38
|
|
|
39
|
-
credentials =
|
|
40
|
-
client =
|
|
39
|
+
credentials = TableauCredentials(**kwargs)
|
|
40
|
+
client = TableauClient(
|
|
41
41
|
credentials,
|
|
42
42
|
with_pulse=with_pulse,
|
|
43
43
|
override_page_size=page_size,
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from collections.abc import Iterator
|
|
2
|
-
from
|
|
3
|
+
from functools import partial
|
|
4
|
+
from typing import Iterable, Optional
|
|
3
5
|
|
|
4
6
|
import requests
|
|
7
|
+
from requests import Response
|
|
5
8
|
|
|
6
9
|
from ....utils import (
|
|
7
10
|
APIClient,
|
|
8
11
|
BearerAuth,
|
|
9
12
|
RequestSafeMode,
|
|
10
13
|
build_url,
|
|
14
|
+
fetch_all_pages,
|
|
11
15
|
handle_response,
|
|
12
16
|
)
|
|
13
17
|
from ..assets import (
|
|
@@ -19,9 +23,7 @@ from .credentials import (
|
|
|
19
23
|
from .endpoints import (
|
|
20
24
|
ThoughtspotEndpointFactory,
|
|
21
25
|
)
|
|
22
|
-
from .
|
|
23
|
-
usage_liveboard_reader,
|
|
24
|
-
)
|
|
26
|
+
from .pagination import METADATA_BATCH_SIZE, ThoughtSpotPagination
|
|
25
27
|
|
|
26
28
|
_AUTH_TIMEOUT_S = 60
|
|
27
29
|
_THOUGHTSPOT_HEADERS = {
|
|
@@ -29,7 +31,6 @@ _THOUGHTSPOT_HEADERS = {
|
|
|
29
31
|
"Accept": "application/json",
|
|
30
32
|
"Content-Type": "application/json",
|
|
31
33
|
}
|
|
32
|
-
_METADATA_BATCH_SIZE = 100
|
|
33
34
|
# https://docs.thoughtspot.com/cloud/latest/object-usage-liveboard
|
|
34
35
|
_OBJECT_USAGE_LIVEBOARD = "Object Usage"
|
|
35
36
|
_ANSWER_USAGE_VIZ = "Answer Usage, by User"
|
|
@@ -40,6 +41,9 @@ _LIVEBOARD_USAGE_VIZ = "Popular Liveboards Last 30 Days"
|
|
|
40
41
|
THOUGHTSPOT_SAFE_MODE = RequestSafeMode()
|
|
41
42
|
|
|
42
43
|
|
|
44
|
+
logger = logging.getLogger(__name__)
|
|
45
|
+
|
|
46
|
+
|
|
43
47
|
class ThoughtspotBearerAuth(BearerAuth):
|
|
44
48
|
def __init__(self, host: str, token_payload: dict[str, str]):
|
|
45
49
|
auth_endpoint = ThoughtspotEndpointFactory.authentication()
|
|
@@ -86,7 +90,7 @@ class ThoughtspotClient(APIClient):
|
|
|
86
90
|
search_filters = {
|
|
87
91
|
"metadata": [{"type": metadata_type}],
|
|
88
92
|
"include_details": True,
|
|
89
|
-
"record_size":
|
|
93
|
+
"record_size": METADATA_BATCH_SIZE,
|
|
90
94
|
"record_offset": offset,
|
|
91
95
|
}
|
|
92
96
|
if identifier:
|
|
@@ -100,9 +104,9 @@ class ThoughtspotClient(APIClient):
|
|
|
100
104
|
data=search_filters,
|
|
101
105
|
)
|
|
102
106
|
yield from metadata
|
|
103
|
-
if len(metadata) <
|
|
107
|
+
if len(metadata) < METADATA_BATCH_SIZE:
|
|
104
108
|
break
|
|
105
|
-
offset = offset +
|
|
109
|
+
offset = offset + METADATA_BATCH_SIZE
|
|
106
110
|
|
|
107
111
|
def _get_all_answers(self) -> Iterator[dict]:
|
|
108
112
|
yield from self._metadata_search(metadata_type="ANSWER")
|
|
@@ -120,7 +124,7 @@ class ThoughtspotClient(APIClient):
|
|
|
120
124
|
self,
|
|
121
125
|
liveboard_name: str,
|
|
122
126
|
visualization_name: str,
|
|
123
|
-
) -> Iterator[
|
|
127
|
+
) -> Iterator[list[list]]:
|
|
124
128
|
"""
|
|
125
129
|
Yields the data of a given visualization in the given liveboard.
|
|
126
130
|
ThoughtSpot maintains two system liveboards with stats about data usage,
|
|
@@ -133,29 +137,62 @@ class ThoughtspotClient(APIClient):
|
|
|
133
137
|
)
|
|
134
138
|
liveboard_id = usage_liveboard["metadata_id"]
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
def handler(response: Response) -> dict:
|
|
141
|
+
response_dict = response.json()
|
|
142
|
+
contents = response_dict.get("contents", [])
|
|
143
|
+
if not contents:
|
|
144
|
+
logger.warning("No data found in response")
|
|
145
|
+
return dict()
|
|
146
|
+
return contents[0]
|
|
147
|
+
|
|
148
|
+
request = partial(
|
|
149
|
+
self._post,
|
|
150
|
+
endpoint=ThoughtspotEndpointFactory.liveboard_data(),
|
|
139
151
|
data={
|
|
140
152
|
"metadata_identifier": liveboard_id,
|
|
141
|
-
"file_format": "CSV",
|
|
142
153
|
"visualization_identifiers": [visualization_name],
|
|
154
|
+
"record_offset": 0,
|
|
155
|
+
"record_size": METADATA_BATCH_SIZE,
|
|
143
156
|
},
|
|
144
|
-
handler=
|
|
157
|
+
handler=handler,
|
|
145
158
|
)
|
|
146
|
-
yield from
|
|
159
|
+
yield from fetch_all_pages(request, ThoughtSpotPagination)
|
|
147
160
|
|
|
148
161
|
def _get_answer_usages(self) -> Iterator[dict]:
|
|
149
|
-
|
|
162
|
+
"""
|
|
163
|
+
Returns the usage data of saved Answers, which is found in a visualization
|
|
164
|
+
of the "Object Usage" liveboard.
|
|
165
|
+
Each data row returned by the API is transformed from a list into a dictionary.
|
|
166
|
+
The columns are explicitly listed here because in the API response,
|
|
167
|
+
there is a mismatch between the number of column names and the number
|
|
168
|
+
of values per data row.
|
|
169
|
+
"""
|
|
170
|
+
data: Iterable[list[list]] = self._get_usages(
|
|
150
171
|
liveboard_name=_OBJECT_USAGE_LIVEBOARD,
|
|
151
172
|
visualization_name=_ANSWER_USAGE_VIZ,
|
|
152
173
|
)
|
|
174
|
+
columns = (
|
|
175
|
+
"Answer name",
|
|
176
|
+
"Number of unique users",
|
|
177
|
+
"Count of object interactions",
|
|
178
|
+
)
|
|
179
|
+
for row in data:
|
|
180
|
+
yield dict(zip(columns, row))
|
|
153
181
|
|
|
154
182
|
def _get_liveboards_usages(self) -> Iterator[dict]:
|
|
155
|
-
|
|
183
|
+
"""
|
|
184
|
+
Returns the usage data of Liveboards, which is found in a visualization
|
|
185
|
+
of the "User Adoption" liveboard.
|
|
186
|
+
Each data row returned by the API is transformed from a list into a dictionary.
|
|
187
|
+
See `_get_answer_usages` regarding the columns list.
|
|
188
|
+
"""
|
|
189
|
+
data: Iterable[list[list]] = self._get_usages(
|
|
156
190
|
liveboard_name=_USER_ADOPTION_LIVEBOARD,
|
|
157
191
|
visualization_name=_LIVEBOARD_USAGE_VIZ,
|
|
158
192
|
)
|
|
193
|
+
columns = ("Pinboard", "Unique Number of User", "Pinboard Views")
|
|
194
|
+
for row in data:
|
|
195
|
+
yield dict(zip(columns, row))
|
|
159
196
|
|
|
160
197
|
def fetch(self, asset: ThoughtspotAsset) -> Iterator[dict]:
|
|
161
198
|
if asset == ThoughtspotAsset.ANSWERS:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from pydantic import ConfigDict, Field
|
|
2
|
+
|
|
3
|
+
from ....utils import PaginationModel
|
|
4
|
+
|
|
5
|
+
METADATA_BATCH_SIZE = 100
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ThoughtSpotPagination(PaginationModel):
|
|
9
|
+
data_rows: list = Field(default_factory=list)
|
|
10
|
+
record_offset: int
|
|
11
|
+
record_size: int
|
|
12
|
+
|
|
13
|
+
model_config = ConfigDict(
|
|
14
|
+
populate_by_name=True,
|
|
15
|
+
from_attributes=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def is_last(self) -> bool:
|
|
19
|
+
return len(self.data_rows) < METADATA_BATCH_SIZE
|
|
20
|
+
|
|
21
|
+
def next_page_payload(self) -> dict:
|
|
22
|
+
return {"record_offset": self.record_offset + METADATA_BATCH_SIZE}
|
|
23
|
+
|
|
24
|
+
def page_results(self) -> list:
|
|
25
|
+
return self.data_rows
|