castor-extractor 0.24.10__tar.gz → 0.24.13__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.10 → castor_extractor-0.24.13}/CHANGELOG.md +12 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/PKG-INFO +21 -4
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/README.md +5 -2
- castor_extractor-0.24.13/castor_extractor/commands/extract_strategy.py +26 -0
- castor_extractor-0.24.13/castor_extractor/visualization/strategy/__init__.py +3 -0
- castor_extractor-0.24.13/castor_extractor/visualization/strategy/assets.py +14 -0
- castor_extractor-0.24.13/castor_extractor/visualization/strategy/client/__init__.py +2 -0
- castor_extractor-0.24.13/castor_extractor/visualization/strategy/client/client.py +313 -0
- castor_extractor-0.24.13/castor_extractor/visualization/strategy/client/credentials.py +38 -0
- castor_extractor-0.24.13/castor_extractor/visualization/strategy/extract.py +43 -0
- castor_extractor-0.24.13/castor_extractor/warehouse/redshift/queries/view_ddl.sql +33 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/pyproject.toml +6 -2
- castor_extractor-0.24.10/castor_extractor/warehouse/redshift/queries/view_ddl.sql +0 -19
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/Dockerfile +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/DockerfileUsage.md +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/LICENCE +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_bigquery.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_confluence.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_databricks.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_domo.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_looker.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_looker_studio.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_metabase_api.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_metabase_db.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_mode.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_mysql.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_notion.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_postgres.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_powerbi.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_qlik.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_redshift.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_salesforce.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_salesforce_reporting.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_sigma.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_snowflake.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_sqlserver.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_tableau.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_thoughtspot.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/file_check.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/upload.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/column.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/column_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/enums.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/file.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/file_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/file_test_users.csv +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/file_test_users_valid.csv +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/templates/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/file_checker/templates/generic_warehouse.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/confluence/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/knowledge/notion/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/logger.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/quality/soda/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/endpoint.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/type.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/utils.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/transformation/coalesce/client/utils_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/types.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/constant.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/env.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/env_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/settings.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/upload.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/upload_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/uploader/utils.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/argument_parser.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/argument_parser_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/batch.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/batch_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/abstract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/auth.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/auth_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/pagination_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/safe_request.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/safe_request_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/utils.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/api/utils_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/postgres.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/uri.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/client/uri_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/collection.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/collection_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/dbt/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/dbt/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/dbt/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/dbt/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/dbt/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/deprecate.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/env.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/files.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/files_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/formatter.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/formatter_test.csv +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/formatter_test.json +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/formatter_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/json_stream_write.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/load.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/object.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/object_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/pager/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/pager/pager.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/pager/pager_on_id.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/pager/pager_on_id_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/pager/pager_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/retry.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/retry_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/safe.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/safe_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/credentials_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/salesforce/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/store.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/string.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/string_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/time.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/time_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/type.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/validation.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/validation_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/utils/write.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/client/pagination_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/domo/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/extraction_parameters.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/sdk.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/sdk_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/api/utils.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/constant.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/fields.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/fields_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker/multithreading.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/enums.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/queries/query.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/client/scopes.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/looker_studio/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/api/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/api/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/api/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/api/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/base_url.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/card.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/collection.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/dashboard.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/dashboard_cards.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/db/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/decryption.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/decryption_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/client/shared.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/errors.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/metabase/types.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/client/client_test.json +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/client/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/client/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/errors.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/mode/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/authentication.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/credentials_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/powerbi/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/error.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/error_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/json_rpc.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/json_rpc_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/engine/websocket.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/master.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/rest.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/client/rest_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/qlik/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/salesforce_reporting/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/salesforce_reporting/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/salesforce_reporting/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/salesforce_reporting/client/rest.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/salesforce_reporting/client/soql.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/salesforce_reporting/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/sigma/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/client_metadata_api.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/client_metadata_api_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/client_rest_api.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/client_tsc.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/errors.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/gql_queries.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/client/rest_fields.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/tableau/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/assets.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/client/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/client/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/client/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/client/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/client/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/visualization/thoughtspot/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/asset.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/asset_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/time_filter.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/abstract/time_filter_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/column.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/cte/sharded.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/query.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/schema.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/table_with_tags.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/bigquery/types.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/api_client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/api_client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/endpoints.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/enums.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/format.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/format_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/lineage.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/lineage_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/sql_client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/types.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/utils.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/databricks/utils_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/column.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/query.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/schema.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/mysql/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/column.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/group.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/schema.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/postgres/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/extract_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/column.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/group.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/query.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/query_serverless.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/schema.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/table_freshness.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/redshift/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/constants.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/format.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/format_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/pagination.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/salesforce/soql.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/client_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/credentials.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/credentials_test.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/column.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/column_lineage.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/function.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/grant_to_role.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/grant_to_user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/query.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/role.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/schema.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/queries/view_ddl.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/snowflake/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/__init__.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/client.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/extract.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/queries/.sqlfluff +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/queries/column.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/queries/database.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/queries/schema.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/queries/table.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/queries/user.sql +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/sqlserver/query.py +0 -0
- {castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/warehouse/synapse/queries/column.sql +0 -0
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.24.13 - 2025-05-05
|
|
4
|
+
|
|
5
|
+
* Rollback cloud-storage version as it's not compatible with Keboola
|
|
6
|
+
|
|
7
|
+
## 0.24.12 - 2025-05-05
|
|
8
|
+
|
|
9
|
+
* Redshift - fix query definition of materialized views
|
|
10
|
+
|
|
11
|
+
## 0.24.11 - 2025-05-05
|
|
12
|
+
|
|
13
|
+
* add support for Strategy (formerly MicroStrategy)
|
|
14
|
+
|
|
3
15
|
## 0.24.10 - 2025-04-30
|
|
4
16
|
|
|
5
17
|
* Tableau - skip warnings instead of raising an error
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: castor-extractor
|
|
3
|
-
Version: 0.24.
|
|
3
|
+
Version: 0.24.13
|
|
4
4
|
Summary: Extract your metadata assets.
|
|
5
5
|
Home-page: https://www.castordoc.com/
|
|
6
6
|
License: EULA
|
|
@@ -28,6 +28,7 @@ Provides-Extra: qlik
|
|
|
28
28
|
Provides-Extra: redshift
|
|
29
29
|
Provides-Extra: snowflake
|
|
30
30
|
Provides-Extra: sqlserver
|
|
31
|
+
Provides-Extra: strategy
|
|
31
32
|
Provides-Extra: tableau
|
|
32
33
|
Requires-Dist: cryptography (>=43.0.0,<44.0.0) ; extra == "snowflake"
|
|
33
34
|
Requires-Dist: databricks-sql-connector (==3.6.0) ; extra == "databricks" or extra == "all"
|
|
@@ -35,11 +36,12 @@ Requires-Dist: google-api-core (>=2.1.1,<3.0.0)
|
|
|
35
36
|
Requires-Dist: google-api-python-client (>=2.121.0,<3.0.0) ; extra == "lookerstudio" or extra == "all"
|
|
36
37
|
Requires-Dist: google-auth (>=2,<3)
|
|
37
38
|
Requires-Dist: google-cloud-core (>=2.1.0,<3.0.0)
|
|
38
|
-
Requires-Dist: google-cloud-storage (>=3
|
|
39
|
+
Requires-Dist: google-cloud-storage (>=2,<3)
|
|
39
40
|
Requires-Dist: google-resumable-media (>=2.0.3,<3.0.0)
|
|
40
41
|
Requires-Dist: googleapis-common-protos (>=1.53.0,<2.0.0)
|
|
41
42
|
Requires-Dist: looker-sdk (>=25.0.0,<26.0.0) ; extra == "looker" or extra == "all"
|
|
42
43
|
Requires-Dist: msal (>=1.20.0,<2.0.0) ; extra == "powerbi" or extra == "all"
|
|
44
|
+
Requires-Dist: mstrio-py (>=11.5.3.101,<12.0.0.0) ; (python_version >= "3.10") and (extra == "strategy" or extra == "all")
|
|
43
45
|
Requires-Dist: numpy (<2) ; extra == "bigquery" or extra == "databricks" or extra == "all"
|
|
44
46
|
Requires-Dist: numpy (>=1.26) ; (python_version >= "3.12" and python_version < "3.13") and (extra == "bigquery" or extra == "databricks" or extra == "all")
|
|
45
47
|
Requires-Dist: pandas (>=2.1) ; (python_version >= "3.12" and python_version < "3.13") and (extra == "databricks" or extra == "all")
|
|
@@ -103,6 +105,8 @@ It also embeds utilities to help you push your metadata to Castor:
|
|
|
103
105
|
Requirements: **python3.9+**
|
|
104
106
|
<img src="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" width=20 />
|
|
105
107
|
|
|
108
|
+
**Note:** The Strategy command requires **python3.10+**. All other modules work with python3.9+.
|
|
109
|
+
|
|
106
110
|
### Create castor-env
|
|
107
111
|
|
|
108
112
|
We advise to create a dedicated [Python environment](https://docs.python.org/3/library/venv.html).
|
|
@@ -181,6 +185,7 @@ pip install castor-extractor[postgres]
|
|
|
181
185
|
pip install castor-extractor[redshift]
|
|
182
186
|
pip install castor-extractor[snowflake]
|
|
183
187
|
pip install castor-extractor[sqlserver]
|
|
188
|
+
pip install castor-extractor[strategy]
|
|
184
189
|
pip install castor-extractor[tableau]
|
|
185
190
|
```
|
|
186
191
|
|
|
@@ -204,12 +209,24 @@ export CASTOR_OUTPUT_DIRECTORY="/tmp/castor"
|
|
|
204
209
|
|
|
205
210
|
## Contact
|
|
206
211
|
|
|
207
|
-
For any questions or bug report, contact us at [support@
|
|
212
|
+
For any questions or bug report, contact us at [support@coalesce.io](mailto:support@coalesce.io)
|
|
208
213
|
|
|
209
|
-
[
|
|
214
|
+
[Catalog from Coalesce](https://castordoc.com) helps you find, understand, use your data assets
|
|
210
215
|
|
|
211
216
|
# Changelog
|
|
212
217
|
|
|
218
|
+
## 0.24.13 - 2025-05-05
|
|
219
|
+
|
|
220
|
+
* Rollback cloud-storage version as it's not compatible with Keboola
|
|
221
|
+
|
|
222
|
+
## 0.24.12 - 2025-05-05
|
|
223
|
+
|
|
224
|
+
* Redshift - fix query definition of materialized views
|
|
225
|
+
|
|
226
|
+
## 0.24.11 - 2025-05-05
|
|
227
|
+
|
|
228
|
+
* add support for Strategy (formerly MicroStrategy)
|
|
229
|
+
|
|
213
230
|
## 0.24.10 - 2025-04-30
|
|
214
231
|
|
|
215
232
|
* Tableau - skip warnings instead of raising an error
|
|
@@ -37,6 +37,8 @@ It also embeds utilities to help you push your metadata to Castor:
|
|
|
37
37
|
Requirements: **python3.9+**
|
|
38
38
|
<img src="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" width=20 />
|
|
39
39
|
|
|
40
|
+
**Note:** The Strategy command requires **python3.10+**. All other modules work with python3.9+.
|
|
41
|
+
|
|
40
42
|
### Create castor-env
|
|
41
43
|
|
|
42
44
|
We advise to create a dedicated [Python environment](https://docs.python.org/3/library/venv.html).
|
|
@@ -115,6 +117,7 @@ pip install castor-extractor[postgres]
|
|
|
115
117
|
pip install castor-extractor[redshift]
|
|
116
118
|
pip install castor-extractor[snowflake]
|
|
117
119
|
pip install castor-extractor[sqlserver]
|
|
120
|
+
pip install castor-extractor[strategy]
|
|
118
121
|
pip install castor-extractor[tableau]
|
|
119
122
|
```
|
|
120
123
|
|
|
@@ -138,6 +141,6 @@ export CASTOR_OUTPUT_DIRECTORY="/tmp/castor"
|
|
|
138
141
|
|
|
139
142
|
## Contact
|
|
140
143
|
|
|
141
|
-
For any questions or bug report, contact us at [support@
|
|
144
|
+
For any questions or bug report, contact us at [support@coalesce.io](mailto:support@coalesce.io)
|
|
142
145
|
|
|
143
|
-
[
|
|
146
|
+
[Catalog from Coalesce](https://castordoc.com) helps you find, understand, use your data assets
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from argparse import ArgumentParser
|
|
3
|
+
|
|
4
|
+
from castor_extractor.utils import parse_filled_arguments # type: ignore
|
|
5
|
+
from castor_extractor.visualization import strategy # type: ignore
|
|
6
|
+
|
|
7
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
parser = ArgumentParser()
|
|
12
|
+
|
|
13
|
+
parser.add_argument("-u", "--username", help="Strategy username")
|
|
14
|
+
parser.add_argument("-p", "--password", help="Strategy password")
|
|
15
|
+
parser.add_argument("-b", "--base-url", help="Strategy instance URL")
|
|
16
|
+
parser.add_argument("-o", "--output", help="Directory to write to")
|
|
17
|
+
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"-i",
|
|
20
|
+
"--project-ids",
|
|
21
|
+
nargs="*",
|
|
22
|
+
help="Optional list of project IDs",
|
|
23
|
+
default=None,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
strategy.extract_all(**parse_filled_arguments(parser))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from ...types import ExternalAsset
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class StrategyAsset(ExternalAsset):
|
|
5
|
+
"""Strategy assets that can be extracted"""
|
|
6
|
+
|
|
7
|
+
ATTRIBUTE = "attribute"
|
|
8
|
+
CUBE = "cube"
|
|
9
|
+
DASHBOARD = "dashboard"
|
|
10
|
+
DOCUMENT = "document"
|
|
11
|
+
FACT = "fact"
|
|
12
|
+
METRIC = "metric"
|
|
13
|
+
REPORT = "report"
|
|
14
|
+
USER = "user"
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Iterator
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any, Callable, Optional
|
|
5
|
+
from urllib.parse import urlparse
|
|
6
|
+
|
|
7
|
+
from mstrio.connection import Connection # type: ignore
|
|
8
|
+
from mstrio.helpers import IServerError # type: ignore
|
|
9
|
+
from mstrio.modeling import ( # type: ignore
|
|
10
|
+
list_attributes,
|
|
11
|
+
list_facts,
|
|
12
|
+
list_metrics,
|
|
13
|
+
)
|
|
14
|
+
from mstrio.project_objects import ( # type: ignore
|
|
15
|
+
Report,
|
|
16
|
+
list_dashboards,
|
|
17
|
+
list_documents,
|
|
18
|
+
list_olap_cubes,
|
|
19
|
+
list_reports,
|
|
20
|
+
)
|
|
21
|
+
from mstrio.server import Environment # type: ignore
|
|
22
|
+
from mstrio.types import ObjectSubTypes, ObjectTypes # type: ignore
|
|
23
|
+
from mstrio.users_and_groups import User, list_users # type: ignore
|
|
24
|
+
from mstrio.utils.entity import Entity # type: ignore
|
|
25
|
+
from mstrio.utils.helper import is_dashboard # type: ignore
|
|
26
|
+
from pydantic import BaseModel, ConfigDict
|
|
27
|
+
|
|
28
|
+
from ..assets import StrategyAsset
|
|
29
|
+
from .credentials import StrategyCredentials
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
_BATCH_SIZE: int = 100
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class URLTemplates(Enum):
|
|
37
|
+
DASHBOARD = (
|
|
38
|
+
"https://{hostname}/MicroStrategyLibrarySTD/app/{project_id}/{id_}"
|
|
39
|
+
)
|
|
40
|
+
DOCUMENT = "https://{hostname}/MicroStrategy/servlet/mstrWeb?documentID={id_}&projectID={project_id}"
|
|
41
|
+
REPORT = "https://{hostname}/MicroStrategy/servlet/mstrWeb?reportID={id_}&projectID={project_id}"
|
|
42
|
+
FOLDER = "https://{hostname}/MicroStrategy/servlet/mstrWeb?folderID={id_}&projectID={project_id}"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _is_dashboard(entity: Entity) -> bool:
|
|
46
|
+
"""
|
|
47
|
+
Returns True if the entity is a Dashboard. They can only be distinguished
|
|
48
|
+
from Documents by checking the `view_media` property.
|
|
49
|
+
"""
|
|
50
|
+
is_type_document = entity.type == ObjectTypes.DOCUMENT_DEFINITION
|
|
51
|
+
return is_type_document and is_dashboard(entity.view_media)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _is_report(entity: Entity) -> bool:
|
|
55
|
+
"""
|
|
56
|
+
Returns True if the entity is a Report. Cubes share the same type as Reports,
|
|
57
|
+
so the subtype must be checked.
|
|
58
|
+
"""
|
|
59
|
+
is_type_report = entity.type == ObjectTypes.REPORT_DEFINITION
|
|
60
|
+
is_subtype_cube = entity.subtype == ObjectSubTypes.OLAP_CUBE.value
|
|
61
|
+
return is_type_report and not is_subtype_cube
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _safe_get_attribute(entity: Entity, attribute: str) -> Optional[str]:
|
|
65
|
+
"""
|
|
66
|
+
Some properties may raise an error. Example: retrieving a Report's `sql` fails if the Report has not been published.
|
|
67
|
+
This safely returns the attribute value, or None if the retrieval fails.
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
value = getattr(entity, attribute)
|
|
71
|
+
except IServerError as e:
|
|
72
|
+
logger.error(f"Could not get {attribute} for entity {entity.id}: {e}")
|
|
73
|
+
value = None
|
|
74
|
+
return value
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Dependency(BaseModel):
|
|
78
|
+
id: str
|
|
79
|
+
name: str
|
|
80
|
+
subtype: int
|
|
81
|
+
type: int
|
|
82
|
+
|
|
83
|
+
model_config = ConfigDict(extra="ignore")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _list_dependencies(entity: Entity) -> list[dict]:
|
|
87
|
+
"""Lists the entity's dependencies, keeping only relevant fields."""
|
|
88
|
+
dependencies: list[dict] = []
|
|
89
|
+
|
|
90
|
+
offset = 0
|
|
91
|
+
while True:
|
|
92
|
+
batch = entity.list_dependencies(offset=offset, limit=_BATCH_SIZE)
|
|
93
|
+
dependencies.extend(batch)
|
|
94
|
+
if len(batch) < _BATCH_SIZE:
|
|
95
|
+
break
|
|
96
|
+
offset += _BATCH_SIZE
|
|
97
|
+
|
|
98
|
+
return [
|
|
99
|
+
Dependency(**dependency).model_dump() for dependency in dependencies
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _level_1_folder_id(folders: list[dict]) -> str:
|
|
104
|
+
"""Searches for the first enclosing folder and returns its ID."""
|
|
105
|
+
for folder in folders:
|
|
106
|
+
if folder["level"] == 1:
|
|
107
|
+
return folder["id"]
|
|
108
|
+
|
|
109
|
+
raise ValueError("No level 1 folder found")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class StrategyClient:
|
|
113
|
+
"""Connect to Strategy through mstrio-py and fetch main assets."""
|
|
114
|
+
|
|
115
|
+
def __init__(self, credentials: StrategyCredentials):
|
|
116
|
+
self.base_url = credentials.base_url
|
|
117
|
+
self.connection = Connection(
|
|
118
|
+
base_url=self.base_url,
|
|
119
|
+
username=credentials.username,
|
|
120
|
+
password=credentials.password,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
self.hostname = urlparse(self.base_url).hostname
|
|
124
|
+
|
|
125
|
+
if credentials.project_ids:
|
|
126
|
+
self.project_ids = credentials.project_ids
|
|
127
|
+
else:
|
|
128
|
+
env = Environment(connection=self.connection)
|
|
129
|
+
self.project_ids = [project.id for project in env.list_projects()]
|
|
130
|
+
|
|
131
|
+
def close(self):
|
|
132
|
+
self.connection.close()
|
|
133
|
+
|
|
134
|
+
def _url(self, entity: Entity) -> str:
|
|
135
|
+
"""
|
|
136
|
+
Formats the right URL.
|
|
137
|
+
* Dashboards : viewed in MicroStrategy
|
|
138
|
+
* Reports and Documents : viewed in MicroStrategy Web
|
|
139
|
+
* other (i.e. Cubes): the URL leads to the folder in MicroStrategy Web
|
|
140
|
+
"""
|
|
141
|
+
if _is_dashboard(entity):
|
|
142
|
+
id_ = entity.id
|
|
143
|
+
template = URLTemplates.DASHBOARD
|
|
144
|
+
|
|
145
|
+
elif entity.type == ObjectTypes.DOCUMENT_DEFINITION:
|
|
146
|
+
id_ = entity.id
|
|
147
|
+
template = URLTemplates.DOCUMENT
|
|
148
|
+
|
|
149
|
+
elif _is_report(entity):
|
|
150
|
+
id_ = entity.id
|
|
151
|
+
template = URLTemplates.REPORT
|
|
152
|
+
|
|
153
|
+
else:
|
|
154
|
+
# default to folder URL
|
|
155
|
+
id_ = _level_1_folder_id(entity.ancestors)
|
|
156
|
+
template = URLTemplates.FOLDER
|
|
157
|
+
|
|
158
|
+
return template.value.format(
|
|
159
|
+
hostname=self.hostname,
|
|
160
|
+
id_=id_,
|
|
161
|
+
project_id=entity.project_id,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def _common_entity_properties(
|
|
165
|
+
self,
|
|
166
|
+
entity: Entity,
|
|
167
|
+
with_url: bool = True,
|
|
168
|
+
with_description: bool = True,
|
|
169
|
+
) -> dict:
|
|
170
|
+
"""
|
|
171
|
+
Returns the entity's properties, including its dependencies
|
|
172
|
+
and optional URL and/or description.
|
|
173
|
+
"""
|
|
174
|
+
dependencies = _list_dependencies(entity)
|
|
175
|
+
owner_id = entity.owner.id if isinstance(entity.owner, User) else None
|
|
176
|
+
properties = {
|
|
177
|
+
"dependencies": dependencies,
|
|
178
|
+
"id": entity.id,
|
|
179
|
+
"location": entity.location,
|
|
180
|
+
"name": entity.name,
|
|
181
|
+
"owner_id": owner_id,
|
|
182
|
+
"subtype": entity.subtype,
|
|
183
|
+
"type": entity.type.value,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if with_url:
|
|
187
|
+
properties["url"] = self._url(entity)
|
|
188
|
+
|
|
189
|
+
if with_description:
|
|
190
|
+
properties["description"] = _safe_get_attribute(
|
|
191
|
+
entity, "description"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return properties
|
|
195
|
+
|
|
196
|
+
def _report_properties(self, report: Report) -> dict[str, Any]:
|
|
197
|
+
"""
|
|
198
|
+
Report properties contain an optional SQL source query. Due to a typing
|
|
199
|
+
bug in the mstrio package, the typing must be ignored.
|
|
200
|
+
"""
|
|
201
|
+
properties = self._common_entity_properties(report) # type: ignore
|
|
202
|
+
properties["url"] = self._url(report) # type: ignore
|
|
203
|
+
properties["sql"] = _safe_get_attribute(report, "sql") # type: ignore
|
|
204
|
+
return properties
|
|
205
|
+
|
|
206
|
+
@staticmethod
|
|
207
|
+
def _user_properties(user: User) -> dict[str, Any]:
|
|
208
|
+
return {
|
|
209
|
+
"id": user.id,
|
|
210
|
+
"name": user.name,
|
|
211
|
+
"username": user.username,
|
|
212
|
+
"email": user.default_email_address,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
def _fetch_entities(
|
|
216
|
+
self,
|
|
217
|
+
extract_callback: Callable,
|
|
218
|
+
with_url: bool = True,
|
|
219
|
+
with_description: bool = True,
|
|
220
|
+
custom_property_extractor: Optional[Callable] = None,
|
|
221
|
+
) -> Iterator[dict[str, Any]]:
|
|
222
|
+
"""
|
|
223
|
+
Yields all entities across all projects using the given retrieval function from the mstrio package.
|
|
224
|
+
"""
|
|
225
|
+
for project_id in self.project_ids:
|
|
226
|
+
self.connection.select_project(project_id=project_id)
|
|
227
|
+
|
|
228
|
+
entities = extract_callback(connection=self.connection)
|
|
229
|
+
|
|
230
|
+
for entity in entities:
|
|
231
|
+
try:
|
|
232
|
+
if custom_property_extractor:
|
|
233
|
+
yield custom_property_extractor(entity)
|
|
234
|
+
else:
|
|
235
|
+
yield self._common_entity_properties(
|
|
236
|
+
entity,
|
|
237
|
+
with_url=with_url,
|
|
238
|
+
with_description=with_description,
|
|
239
|
+
)
|
|
240
|
+
except IServerError as e:
|
|
241
|
+
logger.error(
|
|
242
|
+
f"Could not fetch attributes for entity {entity.id}: {e}"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
def _fetch_attributes(self) -> Iterator[dict[str, Any]]:
|
|
246
|
+
return self._fetch_entities(
|
|
247
|
+
list_attributes,
|
|
248
|
+
with_url=False,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def _fetch_cubes(self) -> Iterator[dict[str, Any]]:
|
|
252
|
+
return self._fetch_entities(list_olap_cubes)
|
|
253
|
+
|
|
254
|
+
def _fetch_dashboards(self) -> Iterator[dict[str, Any]]:
|
|
255
|
+
return self._fetch_entities(list_dashboards)
|
|
256
|
+
|
|
257
|
+
def _fetch_documents(self) -> Iterator[dict[str, Any]]:
|
|
258
|
+
return self._fetch_entities(list_documents)
|
|
259
|
+
|
|
260
|
+
def _fetch_facts(self) -> Iterator[dict[str, Any]]:
|
|
261
|
+
"""Yields all facts. Descriptions are not needed for this entity type."""
|
|
262
|
+
return self._fetch_entities(
|
|
263
|
+
list_facts,
|
|
264
|
+
with_url=False,
|
|
265
|
+
with_description=False,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def _fetch_metrics(self) -> Iterator[dict[str, Any]]:
|
|
269
|
+
return self._fetch_entities(
|
|
270
|
+
list_metrics,
|
|
271
|
+
with_url=False,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
def _fetch_reports(self) -> Iterator[dict[str, Any]]:
|
|
275
|
+
return self._fetch_entities(
|
|
276
|
+
list_reports,
|
|
277
|
+
custom_property_extractor=self._report_properties,
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
def _fetch_users(self) -> Iterator[dict[str, Any]]:
|
|
281
|
+
return self._fetch_entities(
|
|
282
|
+
list_users,
|
|
283
|
+
custom_property_extractor=self._user_properties,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
def fetch(self, asset: StrategyAsset):
|
|
287
|
+
"""Fetch the given asset type from Strategy"""
|
|
288
|
+
if asset == StrategyAsset.ATTRIBUTE:
|
|
289
|
+
yield from self._fetch_attributes()
|
|
290
|
+
|
|
291
|
+
elif asset == StrategyAsset.CUBE:
|
|
292
|
+
yield from self._fetch_cubes()
|
|
293
|
+
|
|
294
|
+
elif asset == StrategyAsset.DASHBOARD:
|
|
295
|
+
yield from self._fetch_dashboards()
|
|
296
|
+
|
|
297
|
+
elif asset == StrategyAsset.DOCUMENT:
|
|
298
|
+
yield from self._fetch_documents()
|
|
299
|
+
|
|
300
|
+
elif asset == StrategyAsset.FACT:
|
|
301
|
+
yield from self._fetch_facts()
|
|
302
|
+
|
|
303
|
+
elif asset == StrategyAsset.METRIC:
|
|
304
|
+
yield from self._fetch_metrics()
|
|
305
|
+
|
|
306
|
+
elif asset == StrategyAsset.REPORT:
|
|
307
|
+
yield from self._fetch_reports()
|
|
308
|
+
|
|
309
|
+
elif asset == StrategyAsset.USER:
|
|
310
|
+
yield from self._fetch_users()
|
|
311
|
+
|
|
312
|
+
else:
|
|
313
|
+
raise NotImplementedError(f"Asset type {asset} not implemented yet")
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, field_validator
|
|
4
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
5
|
+
|
|
6
|
+
STRATEGY_ENV_PREFIX = "CATALOG_STRATEGY_"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StrategyCredentials(BaseSettings):
|
|
10
|
+
model_config = SettingsConfigDict(
|
|
11
|
+
env_prefix=STRATEGY_ENV_PREFIX,
|
|
12
|
+
extra="ignore",
|
|
13
|
+
populate_by_name=True,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
base_url: str
|
|
17
|
+
password: str = Field(repr=False)
|
|
18
|
+
username: str
|
|
19
|
+
|
|
20
|
+
project_ids: Optional[list[str]] = None
|
|
21
|
+
|
|
22
|
+
@field_validator("project_ids", mode="before")
|
|
23
|
+
@classmethod
|
|
24
|
+
def _check_project_ids(cls, project_ids: Any) -> Optional[list[str]]:
|
|
25
|
+
"""
|
|
26
|
+
The project IDs are optional and can be either a list of strings
|
|
27
|
+
or single string with project IDs separated by commas.
|
|
28
|
+
"""
|
|
29
|
+
if project_ids is None:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
if isinstance(project_ids, str):
|
|
33
|
+
return [item.strip() for item in project_ids.split(",")]
|
|
34
|
+
|
|
35
|
+
if isinstance(project_ids, list):
|
|
36
|
+
return project_ids
|
|
37
|
+
|
|
38
|
+
raise ValueError(f"Unexpected type for project_id: {type(project_ids)}")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
from ...utils import (
|
|
6
|
+
OUTPUT_DIR,
|
|
7
|
+
current_timestamp,
|
|
8
|
+
deep_serialize,
|
|
9
|
+
from_env,
|
|
10
|
+
get_output_filename,
|
|
11
|
+
write_json,
|
|
12
|
+
write_summary,
|
|
13
|
+
)
|
|
14
|
+
from .assets import StrategyAsset
|
|
15
|
+
from .client import StrategyClient, StrategyCredentials
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def iterate_all_data(
|
|
21
|
+
client: StrategyClient,
|
|
22
|
+
) -> Iterable[tuple[str, Union[list, dict]]]:
|
|
23
|
+
"""Iterate over the extracted data from Strategy"""
|
|
24
|
+
|
|
25
|
+
for asset in StrategyAsset:
|
|
26
|
+
logger.info(f"Extracting {asset.value.upper()} from REST API")
|
|
27
|
+
data = client.fetch(asset)
|
|
28
|
+
yield asset.name.lower(), list(deep_serialize(data))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def extract_all(**kwargs) -> None:
|
|
32
|
+
_output_directory = kwargs.get("output") or from_env(OUTPUT_DIR)
|
|
33
|
+
credentials = StrategyCredentials(**kwargs)
|
|
34
|
+
|
|
35
|
+
client = StrategyClient(credentials=credentials)
|
|
36
|
+
ts = current_timestamp()
|
|
37
|
+
|
|
38
|
+
for key, data in iterate_all_data(client):
|
|
39
|
+
filename = get_output_filename(key, _output_directory, ts)
|
|
40
|
+
write_json(filename, data)
|
|
41
|
+
|
|
42
|
+
client.close()
|
|
43
|
+
write_summary(_output_directory, ts)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This query was inspired from this thread:
|
|
3
|
+
https://github.com/awslabs/amazon-redshift-utils/blob/master/src/AdminViews/v_generate_view_ddl.sql
|
|
4
|
+
|
|
5
|
+
Notable differences:
|
|
6
|
+
* There is no "--DROP" statement/comment here
|
|
7
|
+
* Left-trimming the view definition is necessary to capture "CREATE" statements starting with whitespaces or line breaks.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
SELECT
|
|
11
|
+
CURRENT_DATABASE() AS database_name,
|
|
12
|
+
n.nspname AS schema_name,
|
|
13
|
+
c.relname AS view_name,
|
|
14
|
+
CASE
|
|
15
|
+
WHEN c.relnatts > 0 THEN
|
|
16
|
+
CASE
|
|
17
|
+
STRPOS(LOWER(LTRIM(pg_get_viewdef(c.oid, TRUE), '\t\r\n ')), 'create')
|
|
18
|
+
WHEN 1 THEN '' -- CREATE statement already present
|
|
19
|
+
ELSE -- No CREATE statement present, so no materialized view anyway
|
|
20
|
+
'CREATE OR REPLACE VIEW ' || QUOTE_IDENT(n.nspname) || '.' || QUOTE_IDENT(c.relname) || ' AS\n'
|
|
21
|
+
END
|
|
22
|
+
|| COALESCE(pg_get_viewdef(c.oid, TRUE), '')
|
|
23
|
+
ELSE COALESCE(pg_get_viewdef(c.oid, TRUE), '')
|
|
24
|
+
END AS view_definition
|
|
25
|
+
FROM
|
|
26
|
+
pg_catalog.pg_class AS c
|
|
27
|
+
INNER JOIN
|
|
28
|
+
pg_catalog.pg_namespace AS n
|
|
29
|
+
ON c.relnamespace = n.oid
|
|
30
|
+
WHERE
|
|
31
|
+
TRUE
|
|
32
|
+
AND relkind = 'v'
|
|
33
|
+
AND n.nspname NOT IN ('information_schema', 'pg_catalog');
|
|
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.2"]
|
|
|
3
3
|
|
|
4
4
|
[tool.poetry]
|
|
5
5
|
name = "castor-extractor"
|
|
6
|
-
version = "0.24.
|
|
6
|
+
version = "0.24.13"
|
|
7
7
|
description = "Extract your metadata assets."
|
|
8
8
|
authors = ["Castor <support@castordoc.com>"]
|
|
9
9
|
license = "EULA"
|
|
@@ -32,11 +32,12 @@ google-api-core = ">=2.1.1, <3.0.0"
|
|
|
32
32
|
google-api-python-client = {version = "^2.121.0", optional = true}
|
|
33
33
|
google-auth = "^2"
|
|
34
34
|
google-cloud-core = ">=2.1.0, <3.0.0"
|
|
35
|
-
google-cloud-storage = "^
|
|
35
|
+
google-cloud-storage = "^2"
|
|
36
36
|
google-resumable-media = "^2.0.3"
|
|
37
37
|
googleapis-common-protos = "^1.53.0"
|
|
38
38
|
looker-sdk = { version = "^25.0.0", optional = true }
|
|
39
39
|
msal = { version = "^1.20.0", optional = true }
|
|
40
|
+
mstrio-py = { version = "^11.5.3.101", python = ">=3.10", optional = true }
|
|
40
41
|
numpy = [ # Subdependency of pyarrow. As numpy add 3.12 in 1.26. And poetry doesn't manage it well.
|
|
41
42
|
{ version = ">=1.26", python = "~3.12", optional = true },
|
|
42
43
|
{ version = "<2", optional = true }, # https://github.com/numpy/numpy/issues/26710 -> pandas isn't compatible with numpy 2
|
|
@@ -87,12 +88,14 @@ snowflake = [
|
|
|
87
88
|
"cryptography",
|
|
88
89
|
]
|
|
89
90
|
sqlserver = ["pymssql"]
|
|
91
|
+
strategy = ["mstrio-py"]
|
|
90
92
|
tableau = ["tableauserverclient"]
|
|
91
93
|
all = [
|
|
92
94
|
"databricks-sql-connector",
|
|
93
95
|
"google-api-python-client",
|
|
94
96
|
"looker-sdk",
|
|
95
97
|
"msal",
|
|
98
|
+
"mstrio-py",
|
|
96
99
|
"numpy",
|
|
97
100
|
"pandas",
|
|
98
101
|
"psycopg2-binary",
|
|
@@ -137,6 +140,7 @@ castor-extract-salesforce-viz = "castor_extractor.commands.extract_salesforce_re
|
|
|
137
140
|
castor-extract-sigma = "castor_extractor.commands.extract_sigma:main"
|
|
138
141
|
castor-extract-snowflake = "castor_extractor.commands.extract_snowflake:main"
|
|
139
142
|
castor-extract-sqlserver = "castor_extractor.commands.extract_sqlserver:main"
|
|
143
|
+
castor-extract-strategy = "castor_extractor.commands.extract_strategy:main"
|
|
140
144
|
castor-extract-tableau = "castor_extractor.commands.extract_tableau:main"
|
|
141
145
|
castor-extract-thoughtspot = "castor_extractor.commands.extract_thoughtspot:main"
|
|
142
146
|
castor-file-check = "castor_extractor.commands.file_check:main"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
-- This query was inspired from this thread:
|
|
2
|
-
-- https://github.com/awslabs/amazon-redshift-utils/blob/master/src/AdminViews/v_generate_view_ddl.sql
|
|
3
|
-
SELECT
|
|
4
|
-
CURRENT_DATABASE() AS database_name,
|
|
5
|
-
n.nspname AS schema_name,
|
|
6
|
-
c.relname AS view_name,
|
|
7
|
-
CASE
|
|
8
|
-
WHEN c.relnatts > 0 THEN 'CREATE OR REPLACE VIEW ' + QUOTE_IDENT(n.nspname) + '.' + QUOTE_IDENT(c.relname) + ' AS\n' + COALESCE(pg_get_viewdef(c.oid, TRUE), '')
|
|
9
|
-
ELSE COALESCE(pg_get_viewdef(c.oid, TRUE), '')
|
|
10
|
-
END AS view_definition
|
|
11
|
-
FROM
|
|
12
|
-
pg_catalog.pg_class AS c
|
|
13
|
-
INNER JOIN
|
|
14
|
-
pg_catalog.pg_namespace AS n
|
|
15
|
-
ON c.relnamespace = n.oid
|
|
16
|
-
WHERE
|
|
17
|
-
TRUE
|
|
18
|
-
AND relkind = 'v'
|
|
19
|
-
AND n.nspname NOT IN ('information_schema', 'pg_catalog');
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{castor_extractor-0.24.10 → castor_extractor-0.24.13}/castor_extractor/commands/extract_bigquery.py
RENAMED
|
File without changes
|
|
File without changes
|