castor-extractor 0.24.0__tar.gz → 0.24.2__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.0 → castor_extractor-0.24.2}/CHANGELOG.md +8 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/PKG-INFO +11 -1
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/README.md +2 -0
- castor_extractor-0.24.2/castor_extractor/commands/extract_looker_studio.py +30 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_tableau.py +2 -2
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/__init__.py +1 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/assets.py +1 -0
- castor_extractor-0.24.2/castor_extractor/visualization/looker_studio/client/client.py +87 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/credentials.py +5 -0
- castor_extractor-0.24.2/castor_extractor/visualization/looker_studio/client/queries/query.sql +52 -0
- castor_extractor-0.24.2/castor_extractor/visualization/looker_studio/extract.py +84 -0
- castor_extractor-0.24.2/castor_extractor/visualization/tableau/__init__.py +3 -0
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/assets.py +4 -4
- castor_extractor-0.24.2/castor_extractor/visualization/tableau/client/__init__.py +2 -0
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/client.py +15 -15
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/client_metadata_api.py +9 -9
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/client_rest_api.py +6 -6
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/client_tsc.py +9 -9
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/credentials.py +2 -2
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/gql_queries.py +8 -8
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/rest_fields.py +10 -10
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/extract.py +7 -7
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/pyproject.toml +2 -2
- castor_extractor-0.24.0/castor_extractor/visualization/looker_studio/client/client.py +0 -37
- castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp/__init__.py +0 -3
- castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp/client/__init__.py +0 -2
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/Dockerfile +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/DockerfileUsage.md +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/LICENCE +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_bigquery.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_confluence.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_databricks.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_domo.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_looker.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_metabase_api.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_metabase_db.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_mode.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_mysql.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_notion.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_postgres.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_powerbi.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_qlik.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_redshift.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_salesforce.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_salesforce_reporting.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_sigma.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_snowflake.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_sqlserver.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/extract_thoughtspot.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/file_check.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/commands/upload.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/column.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/column_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/enums.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/file.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/file_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/file_test_users.csv +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/templates/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/confluence/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/knowledge/notion/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/logger.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/quality/soda/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/types.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/constant.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/env.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/env_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/settings.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/upload.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/upload_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/uploader/utils.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/argument_parser.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/argument_parser_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/abstract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/auth.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/auth_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/pagination_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/safe_request.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/safe_request_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/utils.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/api/utils_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/postgres.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/uri.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/client/uri_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/collection.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/collection_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/dbt/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/dbt/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/dbt/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/dbt/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/dbt/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/deprecate.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/env.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/files.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/files_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/formatter.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/formatter_test.csv +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/formatter_test.json +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/formatter_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/json_stream_write.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/load.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/object.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/object_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/pager/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/pager/pager.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/pager/pager_on_id.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/pager/pager_on_id_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/pager/pager_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/retry.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/retry_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/safe.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/safe_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/credentials_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/salesforce/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/store.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/string.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/string_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/time.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/time_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/type.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/validation.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/validation_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/utils/write.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/client/pagination_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/domo/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/extraction_parameters.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/sdk.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/api/utils.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/constant.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/fields.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/fields_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker/multithreading.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/enums.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/looker_studio/client/scopes.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/api/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/client/shared.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/errors.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/metabase/types.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/client/client_test.json +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/client/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/client/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/errors.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/mode/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/authentication.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/powerbi/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/master.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/rest.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/qlik/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/salesforce_reporting/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/salesforce_reporting/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/salesforce_reporting/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/salesforce_reporting/client/rest.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/salesforce_reporting/client/soql.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/salesforce_reporting/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/sigma/extract.py +0 -0
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/client/errors.py +0 -0
- {castor_extractor-0.24.0/castor_extractor/visualization/tableau_revamp → castor_extractor-0.24.2/castor_extractor/visualization/tableau}/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/assets.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/client/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/client/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/client/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/client/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/client/utils.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/client/utils_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/visualization/thoughtspot/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/asset.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/asset_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/bigquery/types.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/api_client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/api_client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/endpoints.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/enums.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/format.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/format_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/lineage.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/lineage_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/sql_client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/types.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/utils.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/databricks/utils_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/column.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/query.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/schema.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/mysql/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/postgres/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/extract_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/query_serverless.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/redshift/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/constants.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/format.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/format_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/pagination.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/salesforce/soql.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/credentials.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/credentials_test.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/column.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/function.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/query.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/schema.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/snowflake/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/__init__.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/client.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/extract.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/queries/column.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/queries/database.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/queries/schema.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/queries/table.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/queries/user.sql +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/sqlserver/query.py +0 -0
- {castor_extractor-0.24.0 → castor_extractor-0.24.2}/castor_extractor/warehouse/synapse/queries/column.sql +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: castor-extractor
|
|
3
|
-
Version: 0.24.
|
|
3
|
+
Version: 0.24.2
|
|
4
4
|
Summary: Extract your metadata assets.
|
|
5
5
|
Home-page: https://www.castordoc.com/
|
|
6
6
|
License: EULA
|
|
@@ -170,7 +170,9 @@ Depending on your use case, you can also install one of the following `extras`:
|
|
|
170
170
|
|
|
171
171
|
```bash
|
|
172
172
|
pip install castor-extractor[bigquery]
|
|
173
|
+
pip install castor-extractor[databricks]
|
|
173
174
|
pip install castor-extractor[looker]
|
|
175
|
+
pip install castor-extractor[lookerstudio]
|
|
174
176
|
pip install castor-extractor[metabase]
|
|
175
177
|
pip install castor-extractor[mysql]
|
|
176
178
|
pip install castor-extractor[powerbi]
|
|
@@ -208,6 +210,14 @@ For any questions or bug report, contact us at [support@castordoc.com](mailto:su
|
|
|
208
210
|
|
|
209
211
|
# Changelog
|
|
210
212
|
|
|
213
|
+
## 0.24.2 - 2025-03-17
|
|
214
|
+
|
|
215
|
+
* Rename Revamped Tableau Connector classes
|
|
216
|
+
|
|
217
|
+
## 0.24.1 - 2025-03-14
|
|
218
|
+
|
|
219
|
+
* Added support for Looker Studio
|
|
220
|
+
|
|
211
221
|
## 0.24.0 - 2025-03-10
|
|
212
222
|
|
|
213
223
|
* Remove legacy Tableau Connector
|
|
@@ -104,7 +104,9 @@ Depending on your use case, you can also install one of the following `extras`:
|
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
pip install castor-extractor[bigquery]
|
|
107
|
+
pip install castor-extractor[databricks]
|
|
107
108
|
pip install castor-extractor[looker]
|
|
109
|
+
pip install castor-extractor[lookerstudio]
|
|
108
110
|
pip install castor-extractor[metabase]
|
|
109
111
|
pip install castor-extractor[mysql]
|
|
110
112
|
pip install castor-extractor[powerbi]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from argparse import ArgumentParser
|
|
2
|
+
|
|
3
|
+
from castor_extractor.utils import parse_filled_arguments # type: ignore
|
|
4
|
+
from castor_extractor.visualization import looker_studio # type: ignore
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
parser = ArgumentParser()
|
|
9
|
+
parser.add_argument(
|
|
10
|
+
"-c",
|
|
11
|
+
"--credentials",
|
|
12
|
+
help="File path to Service Account credentials with Looker Studio access",
|
|
13
|
+
)
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"-a",
|
|
16
|
+
"--admin-email",
|
|
17
|
+
help="Email of a Google Workspace user with admin access",
|
|
18
|
+
)
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
"-b",
|
|
21
|
+
"--bigquery-credentials",
|
|
22
|
+
help=(
|
|
23
|
+
"Optional: file path to Service Account credentials with BigQuery access. "
|
|
24
|
+
"This can be the same file path as for Looker Studio."
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
parser.add_argument("-o", "--output", help="Directory to write to")
|
|
29
|
+
|
|
30
|
+
looker_studio.extract_all(**parse_filled_arguments(parser))
|
{castor_extractor-0.24.0 → castor_extractor-0.24.2}/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))
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from typing import Iterator, Optional
|
|
2
|
+
|
|
3
|
+
from ....utils import empty_iterator
|
|
4
|
+
from ....warehouse.abstract import WarehouseAsset
|
|
5
|
+
from ....warehouse.bigquery import BigQueryClient, BigQueryQueryBuilder
|
|
6
|
+
from .. import LookerStudioAsset
|
|
7
|
+
from .admin_sdk_client import USER_EMAIL_FIELD, AdminSDKClient
|
|
8
|
+
from .credentials import LookerStudioCredentials
|
|
9
|
+
from .looker_studio_api_client import LookerStudioAPIClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LookerStudioQueryBuilder(BigQueryQueryBuilder):
|
|
13
|
+
def job_history_queries(self) -> list:
|
|
14
|
+
"""
|
|
15
|
+
This class and method are a convenient workaround to build the
|
|
16
|
+
ExtractionQueries which retrieve BigQuery's job history, but filtered on
|
|
17
|
+
Looker Studio only.
|
|
18
|
+
|
|
19
|
+
Compared to the generic BigQuery query history, only the SQL "template"
|
|
20
|
+
changes. By defining this class here, this will pick the SQL file
|
|
21
|
+
`queries/query.sql` located in the same directory as this file.
|
|
22
|
+
"""
|
|
23
|
+
return super().build(WarehouseAsset.QUERY) # type: ignore
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LookerStudioClient:
|
|
27
|
+
"""
|
|
28
|
+
Acts as a wrapper class to fetch Looker Studio assets, which requires
|
|
29
|
+
coordinating calls between the Admin SDK API and the Looker Studio API.
|
|
30
|
+
|
|
31
|
+
If the BigQuery credentials are provided, it can also fetch the source queries
|
|
32
|
+
of BigQuery data sources.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
credentials: LookerStudioCredentials,
|
|
38
|
+
bigquery_credentials: Optional[dict] = None,
|
|
39
|
+
):
|
|
40
|
+
self.admin_sdk_client = AdminSDKClient(credentials)
|
|
41
|
+
self.looker_studio_client = LookerStudioAPIClient(credentials)
|
|
42
|
+
|
|
43
|
+
self.bigquery_client: Optional[BigQueryClient] = None
|
|
44
|
+
if bigquery_credentials:
|
|
45
|
+
self.bigquery_client = BigQueryClient(bigquery_credentials)
|
|
46
|
+
|
|
47
|
+
def _get_assets(self) -> Iterator[dict]:
|
|
48
|
+
"""
|
|
49
|
+
Extracts reports and data sources user by user.
|
|
50
|
+
"""
|
|
51
|
+
users = self.admin_sdk_client.list_users()
|
|
52
|
+
|
|
53
|
+
for user in users:
|
|
54
|
+
email = user[USER_EMAIL_FIELD]
|
|
55
|
+
yield from self.looker_studio_client.fetch_user_assets(email)
|
|
56
|
+
|
|
57
|
+
def _get_source_queries(self) -> Iterator[dict]:
|
|
58
|
+
"""
|
|
59
|
+
Extracts the BigQuery jobs triggered by Looker Studio. The last job
|
|
60
|
+
per data source is returned.
|
|
61
|
+
"""
|
|
62
|
+
if not self.bigquery_client:
|
|
63
|
+
return empty_iterator()
|
|
64
|
+
|
|
65
|
+
query_builder = LookerStudioQueryBuilder(
|
|
66
|
+
regions=self.bigquery_client.get_regions(),
|
|
67
|
+
datasets=self.bigquery_client.get_datasets(),
|
|
68
|
+
extended_regions=self.bigquery_client.get_extended_regions(),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
queries = query_builder.job_history_queries()
|
|
72
|
+
|
|
73
|
+
for query in queries:
|
|
74
|
+
yield from self.bigquery_client.execute(query)
|
|
75
|
+
|
|
76
|
+
def fetch(self, asset: LookerStudioAsset) -> Iterator[dict]:
|
|
77
|
+
if asset == LookerStudioAsset.ASSETS:
|
|
78
|
+
yield from self._get_assets()
|
|
79
|
+
|
|
80
|
+
elif asset == LookerStudioAsset.SOURCE_QUERIES:
|
|
81
|
+
yield from self._get_source_queries()
|
|
82
|
+
|
|
83
|
+
elif asset == LookerStudioAsset.VIEW_ACTIVITY:
|
|
84
|
+
yield from self.admin_sdk_client.list_view_events()
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
raise ValueError(f"The asset {asset}, is not supported")
|
|
@@ -2,6 +2,11 @@ from pydantic import BaseModel, SecretStr, field_serializer
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class LookerStudioCredentials(BaseModel):
|
|
5
|
+
"""
|
|
6
|
+
Looker Studio Credentials match the Service Account credentials JSON
|
|
7
|
+
but with an additional admin_email field.
|
|
8
|
+
"""
|
|
9
|
+
|
|
5
10
|
admin_email: str
|
|
6
11
|
auth_provider_x509_cert_url: str
|
|
7
12
|
auth_uri: str
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Gets the query jobs triggered by Looker Studio when refreshing a BigQuery data source. Only the latest query per
|
|
3
|
+
data source is selected.
|
|
4
|
+
|
|
5
|
+
The `labels` column should indicate the `looker_studio_datasource_id` that triggered the job. In some cases, it also
|
|
6
|
+
contains a `looker_studio_report_id` value, which gives us a link between the data source and a report.
|
|
7
|
+
*/
|
|
8
|
+
WITH ranked_by_datasource AS (
|
|
9
|
+
SELECT
|
|
10
|
+
creation_time,
|
|
11
|
+
project_id AS database_name,
|
|
12
|
+
user_email,
|
|
13
|
+
query AS query_text,
|
|
14
|
+
referenced_tables,
|
|
15
|
+
labels,
|
|
16
|
+
ROW_NUMBER() OVER (
|
|
17
|
+
PARTITION BY (
|
|
18
|
+
SELECT
|
|
19
|
+
label.value
|
|
20
|
+
FROM
|
|
21
|
+
UNNEST(labels) AS label
|
|
22
|
+
WHERE
|
|
23
|
+
label.key = 'looker_studio_datasource_id'
|
|
24
|
+
)
|
|
25
|
+
ORDER BY
|
|
26
|
+
creation_time DESC
|
|
27
|
+
) AS row_num
|
|
28
|
+
FROM
|
|
29
|
+
`{project}.region-{region}.INFORMATION_SCHEMA.JOBS_BY_PROJECT`
|
|
30
|
+
WHERE
|
|
31
|
+
job_type = 'QUERY'
|
|
32
|
+
AND EXISTS (
|
|
33
|
+
SELECT
|
|
34
|
+
1
|
|
35
|
+
FROM
|
|
36
|
+
UNNEST(labels) AS label
|
|
37
|
+
WHERE
|
|
38
|
+
label.key = 'requestor'
|
|
39
|
+
AND label.value = 'looker_studio'
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
SELECT
|
|
43
|
+
creation_time,
|
|
44
|
+
database_name,
|
|
45
|
+
user_email,
|
|
46
|
+
query_text,
|
|
47
|
+
referenced_tables,
|
|
48
|
+
labels
|
|
49
|
+
FROM
|
|
50
|
+
ranked_by_datasource
|
|
51
|
+
WHERE
|
|
52
|
+
row_num = 1;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from typing import Optional, Union, cast
|
|
5
|
+
|
|
6
|
+
from ...utils import (
|
|
7
|
+
OUTPUT_DIR,
|
|
8
|
+
current_timestamp,
|
|
9
|
+
deep_serialize,
|
|
10
|
+
from_env,
|
|
11
|
+
get_output_filename,
|
|
12
|
+
write_json,
|
|
13
|
+
write_summary,
|
|
14
|
+
)
|
|
15
|
+
from .assets import LookerStudioAsset
|
|
16
|
+
from .client import LookerStudioClient, LookerStudioCredentials
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
APPLICATION_CREDENTIALS = "GOOGLE_APPLICATION_CREDENTIALS"
|
|
21
|
+
LOOKER_STUDIO_ADMIN_EMAIL = "CASTOR_LOOKER_STUDIO_ADMIN_EMAIL"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def iterate_all_data(
|
|
25
|
+
client: LookerStudioClient,
|
|
26
|
+
) -> Iterable[tuple[LookerStudioAsset, Union[list, dict]]]:
|
|
27
|
+
for asset in LookerStudioAsset:
|
|
28
|
+
logger.info(f"Extracting {asset.name} from API")
|
|
29
|
+
data = list(deep_serialize(client.fetch(asset)))
|
|
30
|
+
yield asset, data
|
|
31
|
+
logger.info(f"Extracted {len(data)} {asset.name} from API")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _credentials(params: dict) -> LookerStudioCredentials:
|
|
35
|
+
"""
|
|
36
|
+
Builds the Looker Studio credentials by combining the Service Account
|
|
37
|
+
credentials with the admin email.
|
|
38
|
+
"""
|
|
39
|
+
path = params.get("credentials") or from_env(APPLICATION_CREDENTIALS)
|
|
40
|
+
logger.info(f"Looker Studio credentials loaded from {path}")
|
|
41
|
+
with open(path) as file:
|
|
42
|
+
credentials = cast(dict, json.load(file))
|
|
43
|
+
|
|
44
|
+
admin_email = params.get("admin_email") or from_env(
|
|
45
|
+
LOOKER_STUDIO_ADMIN_EMAIL
|
|
46
|
+
)
|
|
47
|
+
credentials["admin_email"] = admin_email
|
|
48
|
+
return LookerStudioCredentials(**credentials)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _bigquery_credentials_or_none(params: dict) -> Optional[dict]:
|
|
52
|
+
"""Extracts optional GCP credentials to access BigQuery"""
|
|
53
|
+
path = params.get("bigquery_credentials") or from_env(
|
|
54
|
+
APPLICATION_CREDENTIALS,
|
|
55
|
+
allow_missing=True,
|
|
56
|
+
)
|
|
57
|
+
if not path:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
logger.info(f"BigQuery credentials loaded from {path}")
|
|
61
|
+
with open(path) as file:
|
|
62
|
+
return cast(dict, json.load(file))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def extract_all(**kwargs) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Extracts data from Looker Studio and stores the output files locally under
|
|
68
|
+
the given output_directory.
|
|
69
|
+
"""
|
|
70
|
+
output_directory = kwargs.get("output") or from_env(OUTPUT_DIR)
|
|
71
|
+
credentials = _credentials(kwargs)
|
|
72
|
+
bigquery_credentials = _bigquery_credentials_or_none(kwargs)
|
|
73
|
+
|
|
74
|
+
client = LookerStudioClient(
|
|
75
|
+
credentials=credentials,
|
|
76
|
+
bigquery_credentials=bigquery_credentials,
|
|
77
|
+
)
|
|
78
|
+
ts = current_timestamp()
|
|
79
|
+
|
|
80
|
+
for key, data in iterate_all_data(client):
|
|
81
|
+
filename = get_output_filename(key.name.lower(), output_directory, ts)
|
|
82
|
+
write_json(filename, data)
|
|
83
|
+
|
|
84
|
+
write_summary(output_directory, ts)
|
|
@@ -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
|