snowflake-data-exchange-agent 1.2.0__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.
- snowflake_data_exchange_agent-1.2.0/.gitignore +126 -0
- snowflake_data_exchange_agent-1.2.0/PKG-INFO +556 -0
- snowflake_data_exchange_agent-1.2.0/README.md +498 -0
- snowflake_data_exchange_agent-1.2.0/pyproject.toml +189 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/__init__.py +8 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/__version__.py +23 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/__init__.py +9 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/base_config.py +9 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/cli.py +49 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/default.py +30 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/manager.py +133 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/__init__.py +27 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/application.py +85 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/base_section_config.py +104 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/bulk_utilities/__init__.py +16 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/bulk_utilities/base.py +19 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/bulk_utilities/bcp.py +70 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/bulk_utilities/bulk_utility_registry.py +10 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/__init__.py +24 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/base.py +19 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/__init__.py +28 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/base.py +19 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/s3.py +106 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/snowflake/__init__.py +24 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/snowflake/authenticator_type.py +40 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/snowflake/base.py +172 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/snowflake/connection_name.py +47 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/snowflake/external_browser.py +43 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/cloud_storages/snowflake/password.py +52 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/connection_registry.py +10 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/jdbc/__init__.py +18 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/jdbc/base.py +151 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/jdbc/postgresql.py +56 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/connections/jdbc/sqlserver.py +91 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/server.py +42 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/task_sources/__init__.py +14 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/task_sources/api.py +39 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/task_sources/snowflake_stored_procedure.py +45 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/task_sources/task_source.py +21 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/sections/task_sources/task_source_registry.py +10 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/config/toml.py +171 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/configuration_example.toml +39 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/__init__.py +6 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/cloud_storage_types.py +27 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/config_defaults.py +8 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/config_keys.py +41 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/connection_types.py +60 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/container_keys.py +7 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/data_source_types.py +38 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/paths.py +72 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/task_keys.py +12 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/constants/task_source_types.py +26 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/container.py +122 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/custom_exceptions.py +7 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/__init__.py +19 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/base.py +41 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/bcp_data_source.py +289 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/bulk_utility_types.py +22 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/data_source_registry.py +10 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/database_engines.py +87 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_data_source.py +306 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_jar.py +124 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_jar_dict.py +172 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_mappers/README.md +6 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_mappers/__init__.py +13 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_mappers/base_jdbc_mapper.py +41 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_mappers/byte_array_mapper.py +48 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/jdbc_mappers/date_time_offset_mapper.py +46 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/sf_connection.py +323 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/sql_command_type.py +28 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/data_sources/sql_parser.py +69 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/enums/task_status.py +17 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/interfaces/__init__.py +14 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/interfaces/data_source.py +90 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/interfaces/task_queue.py +148 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/interfaces/task_source_adapter.py +55 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/interfaces/uploader.py +114 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/interfaces/wsgi_server.py +17 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/main.py +64 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/providers/storageProvider.py +77 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/queues/__init__.py +6 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/queues/deque_task_queue.py +155 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/queues/sqlite_task_queue.py +340 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/servers/__init__.py +6 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/servers/flask_app.py +216 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/servers/waitress_app.py +64 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/task_sources/__init__.py +21 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/task_sources/api.py +108 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/task_sources/snowflake_stored_procedure.py +193 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/task_sources/task_source_adapter_registry.py +10 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/tasks/__init__.py +6 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/tasks/lease_refresher.py +170 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/tasks/manager.py +334 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/tasks/task.py +32 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/uploaders/amazon_s3_uploader.py +141 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/uploaders/azure_blob_uploader.py +182 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/uploaders/sf_stage_uploader.py +157 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/utils/__init__.py +11 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/utils/base_registry.py +79 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/utils/decorators.py +113 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/utils/file_system.py +69 -0
- snowflake_data_exchange_agent-1.2.0/src/data_exchange_agent/utils/sf_logger.py +184 -0
- snowflake_data_exchange_agent-1.2.0/tests/README.md +200 -0
- snowflake_data_exchange_agent-1.2.0/tests/__init__.py +0 -0
- snowflake_data_exchange_agent-1.2.0/tests/assets/test_db/Step1_create_db.sql +205 -0
- snowflake_data_exchange_agent-1.2.0/tests/assets/test_db/Step2_scale_db.sql +219 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/__init__.py +1 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/__init__.py +1 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/bulk_utilities/__init__.py +1 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/bulk_utilities/test_bcp_bulk_utility_config.py +260 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/bulk_utilities/test_bulk_utility_registry.py +162 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/connections/cloud_storages/test_s3_connection_config.py +482 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/connections/jdbc/test_jdbc_connection_config.py +393 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/connections/jdbc/test_postgresql_connection_config.py +378 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/connections/jdbc/test_sqlserver_connection_config.py +488 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/test_application_config.py +260 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/test_base_config.py +382 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/sections/test_server_config.py +280 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/test_cli_config.py +262 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/test_config_manager.py +269 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/test_default_config.py +258 -0
- snowflake_data_exchange_agent-1.2.0/tests/config/test_toml_config.py +460 -0
- snowflake_data_exchange_agent-1.2.0/tests/constants/__init__.py +1 -0
- snowflake_data_exchange_agent-1.2.0/tests/constants/test_data_source_types.py +104 -0
- snowflake_data_exchange_agent-1.2.0/tests/constants/test_paths.py +239 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/jdbc_mappers/__init__.py +1 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/jdbc_mappers/test_byte_array_mapper.py +134 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/jdbc_mappers/test_date_time_offset_mapper.py +208 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/test_base_data_source.py +180 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/test_bcp_data_source.py +559 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/test_bulk_utility_types.py +160 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/test_data_source_registry.py +257 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/test_jdbc_data_source.py +802 -0
- snowflake_data_exchange_agent-1.2.0/tests/data_sources/test_sql_parser.py +236 -0
- snowflake_data_exchange_agent-1.2.0/tests/task_sources/test_snowflake_stored_procedure.py +564 -0
- snowflake_data_exchange_agent-1.2.0/tests/tasks/test_task.py +297 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_amazon_s3_uploader.py +287 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_api_manager.py +203 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_azure_blob_uploader.py +354 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_constants.py +120 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_container.py +298 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_data_sources_interfaces.py +250 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_deque_task_queue.py +259 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_enums.py +97 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_flask_app.py +359 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_integration.py +274 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_jdbc_jar.py +322 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_jdbc_jar_dict.py +486 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_main.py +163 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_runner.py +79 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_sf_stage_uploader.py +472 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_sqlite_task_queue.py +441 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_storage_provider.py +256 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_task_manager.py +464 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_uploader_interface.py +221 -0
- snowflake_data_exchange_agent-1.2.0/tests/test_waitress_app.py +176 -0
- snowflake_data_exchange_agent-1.2.0/tests/utils/test_decorators.py +284 -0
- snowflake_data_exchange_agent-1.2.0/tests/utils/test_sf_logger.py +374 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[codz]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
*.manifest
|
|
26
|
+
*.spec
|
|
27
|
+
|
|
28
|
+
pip-log.txt
|
|
29
|
+
pip-delete-this-directory.txt
|
|
30
|
+
|
|
31
|
+
htmlcov/
|
|
32
|
+
.tox/
|
|
33
|
+
.nox/
|
|
34
|
+
.coverage
|
|
35
|
+
.coverage.*
|
|
36
|
+
.cache
|
|
37
|
+
nosetests.xml
|
|
38
|
+
coverage.xml
|
|
39
|
+
*.cover
|
|
40
|
+
*.py.cover
|
|
41
|
+
.hypothesis/
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
cover/
|
|
44
|
+
|
|
45
|
+
*.mo
|
|
46
|
+
*.pot
|
|
47
|
+
|
|
48
|
+
*.log
|
|
49
|
+
local_settings.py
|
|
50
|
+
db.sqlite3
|
|
51
|
+
db.sqlite3-journal
|
|
52
|
+
|
|
53
|
+
instance/
|
|
54
|
+
.webassets-cache
|
|
55
|
+
|
|
56
|
+
.scrapy
|
|
57
|
+
|
|
58
|
+
docs/_build/
|
|
59
|
+
|
|
60
|
+
.pybuilder/
|
|
61
|
+
target/
|
|
62
|
+
|
|
63
|
+
.ipynb_checkpoints
|
|
64
|
+
|
|
65
|
+
profile_default/
|
|
66
|
+
ipython_config.py
|
|
67
|
+
|
|
68
|
+
.pdm-python
|
|
69
|
+
.pdm-build/
|
|
70
|
+
.pixi
|
|
71
|
+
__pypackages__/
|
|
72
|
+
|
|
73
|
+
celerybeat-schedule
|
|
74
|
+
celerybeat.pid
|
|
75
|
+
|
|
76
|
+
*.rdb
|
|
77
|
+
*.aof
|
|
78
|
+
*.pid
|
|
79
|
+
|
|
80
|
+
mnesia/
|
|
81
|
+
rabbitmq/
|
|
82
|
+
rabbitmq-data/
|
|
83
|
+
activemq-data/
|
|
84
|
+
|
|
85
|
+
*.sage.py
|
|
86
|
+
|
|
87
|
+
.env
|
|
88
|
+
.envrc
|
|
89
|
+
.venv
|
|
90
|
+
env/
|
|
91
|
+
venv/
|
|
92
|
+
ENV/
|
|
93
|
+
env.bak/
|
|
94
|
+
venv.bak/
|
|
95
|
+
|
|
96
|
+
.spyderproject
|
|
97
|
+
.spyproject
|
|
98
|
+
.ropeproject
|
|
99
|
+
|
|
100
|
+
/site
|
|
101
|
+
|
|
102
|
+
.mypy_cache/
|
|
103
|
+
.dmypy.json
|
|
104
|
+
dmypy.json
|
|
105
|
+
.pyre/
|
|
106
|
+
.pytype/
|
|
107
|
+
|
|
108
|
+
cython_debug/
|
|
109
|
+
.abstra/
|
|
110
|
+
.ruff_cache/
|
|
111
|
+
.pypirc
|
|
112
|
+
|
|
113
|
+
marimo/_static/
|
|
114
|
+
marimo/_lsp/
|
|
115
|
+
__marimo__/
|
|
116
|
+
|
|
117
|
+
.streamlit/secrets.toml
|
|
118
|
+
|
|
119
|
+
.DS_Store
|
|
120
|
+
.AppleDouble
|
|
121
|
+
.LSOverride
|
|
122
|
+
._*
|
|
123
|
+
|
|
124
|
+
configuration.toml
|
|
125
|
+
src/mocked_api/*
|
|
126
|
+
*.code-workspace
|
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: snowflake-data-exchange-agent
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Data exchange agent for migrations and validation
|
|
5
|
+
Project-URL: Bug Tracker, https://github.com/snowflakedb/migrations-data-validation/issues
|
|
6
|
+
Project-URL: Source code, https://github.com/snowflakedb/migrations-data-validation/
|
|
7
|
+
Project-URL: homepage, https://www.snowflake.com/
|
|
8
|
+
Author-email: "Snowflake, Inc." <snowflake-python-libraries-dl@snowflake.com>
|
|
9
|
+
License: Apache License, Version 2.0
|
|
10
|
+
Keywords: Snowflake,analytics,cloud,data,data-analysis,data-analytics,data-engineering,data-management,data-processing,data-science,data-visualization,data-warehouse,database
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Environment :: Other Environment
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Education
|
|
16
|
+
Classifier: Intended Audience :: Information Technology
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: SQL
|
|
22
|
+
Classifier: Topic :: Database
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
24
|
+
Classifier: Topic :: Software Development
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
27
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
+
Requires-Python: <3.13,>=3.10
|
|
29
|
+
Requires-Dist: azure-identity==1.25.0
|
|
30
|
+
Requires-Dist: azure-storage-blob==12.26.0
|
|
31
|
+
Requires-Dist: boto3==1.40.41
|
|
32
|
+
Requires-Dist: dependency-injector==4.48.2
|
|
33
|
+
Requires-Dist: flask==3.1.2
|
|
34
|
+
Requires-Dist: jaydebeapi==1.2.3
|
|
35
|
+
Requires-Dist: psutil==7.1.0
|
|
36
|
+
Requires-Dist: psycopg2-binary==2.9.10
|
|
37
|
+
Requires-Dist: py4j==0.10.9.9
|
|
38
|
+
Requires-Dist: pyarrow==22.0.0
|
|
39
|
+
Requires-Dist: requests==2.32.5
|
|
40
|
+
Requires-Dist: snowflake-connector-python==4.0.0
|
|
41
|
+
Requires-Dist: sqlparse==0.5.4
|
|
42
|
+
Requires-Dist: toml==0.10.2
|
|
43
|
+
Requires-Dist: urllib3==2.6.3
|
|
44
|
+
Requires-Dist: waitress==3.0.2
|
|
45
|
+
Provides-Extra: all
|
|
46
|
+
Requires-Dist: parameterized>=0.9.0; extra == 'all'
|
|
47
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
|
|
48
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == 'all'
|
|
49
|
+
Requires-Dist: pytest>=7.0.0; extra == 'all'
|
|
50
|
+
Requires-Dist: ruff>=0.1.0; extra == 'all'
|
|
51
|
+
Provides-Extra: development
|
|
52
|
+
Requires-Dist: parameterized>=0.9.0; extra == 'development'
|
|
53
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'development'
|
|
54
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == 'development'
|
|
55
|
+
Requires-Dist: pytest>=7.0.0; extra == 'development'
|
|
56
|
+
Requires-Dist: ruff>=0.1.0; extra == 'development'
|
|
57
|
+
Description-Content-Type: text/markdown
|
|
58
|
+
|
|
59
|
+
# Snowflake Data Exchange Agent
|
|
60
|
+
|
|
61
|
+
[](http://www.apache.org/licenses/LICENSE-2.0.txt)
|
|
62
|
+
[](https://www.python.org/downloads/)
|
|
63
|
+
|
|
64
|
+
A REST API service for database migrations and data validation. Supports multiple databases including Snowflake, PostgreSQL, and SQL Server with queue-based task processing.
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Install
|
|
70
|
+
pip install snowflake-data-exchange-agent
|
|
71
|
+
|
|
72
|
+
# Run
|
|
73
|
+
data-exchange-agent --port 8080
|
|
74
|
+
|
|
75
|
+
# Test
|
|
76
|
+
curl http://localhost:8080/health
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
### From PyPI (Production)
|
|
82
|
+
```bash
|
|
83
|
+
pip install snowflake-data-exchange-agent
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Requirements & Dependencies
|
|
87
|
+
|
|
88
|
+
**Python Version**: 3.10, 3.11, or 3.12 (3.13 not yet supported)
|
|
89
|
+
|
|
90
|
+
**Available dependency groups**:
|
|
91
|
+
- `development`: Testing and development tools (pytest, ruff, etc.)
|
|
92
|
+
- `all`: Includes all development dependencies
|
|
93
|
+
|
|
94
|
+
**Core dependencies include**:
|
|
95
|
+
- Snowflake Connector for Python
|
|
96
|
+
- PySpark for data processing
|
|
97
|
+
- Flask + Waitress for REST API
|
|
98
|
+
- PostgreSQL support (psycopg2-binary)
|
|
99
|
+
- AWS SDK (boto3)
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
Create `src/data_exchange_agent/configuration.toml`:
|
|
104
|
+
|
|
105
|
+
```toml
|
|
106
|
+
selected_task_source = "api"
|
|
107
|
+
|
|
108
|
+
[application]
|
|
109
|
+
workers = 4
|
|
110
|
+
task_fetch_interval = 5
|
|
111
|
+
debug_mode = false
|
|
112
|
+
|
|
113
|
+
[task_source.api]
|
|
114
|
+
key = "api-key"
|
|
115
|
+
|
|
116
|
+
[connections.source.<sqlserver|postgresql|teradata>]
|
|
117
|
+
username = "username"
|
|
118
|
+
password = "password"
|
|
119
|
+
database = "database_name"
|
|
120
|
+
host = "127.0.0.1"
|
|
121
|
+
port = <1433|5432|1025>
|
|
122
|
+
|
|
123
|
+
[connections.target.snowflake_connection_name]
|
|
124
|
+
connection_name = "connection_name"
|
|
125
|
+
|
|
126
|
+
[connections.target.s3]
|
|
127
|
+
profile_name = "profile_name"
|
|
128
|
+
bucket_name = "bucket_name"
|
|
129
|
+
|
|
130
|
+
[connections.target.blob]
|
|
131
|
+
connection_string = "DefaultEndpointsProtocol=https;AccountName=account_name;AccountKey=account_key;EndpointSuffix=core.windows.net"
|
|
132
|
+
container_name = "container_name"
|
|
133
|
+
# Optional: Account name and use_default_credential if not using connection string
|
|
134
|
+
account_name="storage_account_name"
|
|
135
|
+
use_default_credential=<True|False>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
For Snowflake, create `~/.snowflake/config.toml`:
|
|
139
|
+
|
|
140
|
+
```toml
|
|
141
|
+
[connections.default]
|
|
142
|
+
account = "your_account.region"
|
|
143
|
+
user = "your_username"
|
|
144
|
+
password = "your_password"
|
|
145
|
+
warehouse = "COMPUTE_WH"
|
|
146
|
+
database = "PRODUCTION_DB"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## API Usage
|
|
150
|
+
|
|
151
|
+
### Command Line
|
|
152
|
+
```bash
|
|
153
|
+
# Basic usage
|
|
154
|
+
data-exchange-agent
|
|
155
|
+
|
|
156
|
+
# Production settings
|
|
157
|
+
data-exchange-agent --workers 8 --port 8080
|
|
158
|
+
|
|
159
|
+
# Debug mode
|
|
160
|
+
data-exchange-agent --debug --port 5001
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Health Check
|
|
164
|
+
```http
|
|
165
|
+
GET /health
|
|
166
|
+
```
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"status": "healthy",
|
|
170
|
+
"version": "0.0.18",
|
|
171
|
+
"database_connections": {
|
|
172
|
+
"snowflake": "connected"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Task Management
|
|
178
|
+
```http
|
|
179
|
+
# Start processing
|
|
180
|
+
GET /handle_tasks
|
|
181
|
+
|
|
182
|
+
# Stop processing
|
|
183
|
+
GET /stop
|
|
184
|
+
|
|
185
|
+
# Get status
|
|
186
|
+
GET /get_handling_tasks_status
|
|
187
|
+
|
|
188
|
+
# Task count
|
|
189
|
+
GET /get_tasks_count
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Add Task
|
|
193
|
+
```http
|
|
194
|
+
POST /tasks
|
|
195
|
+
Content-Type: application/json
|
|
196
|
+
```
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"task_type": "data_extraction",
|
|
200
|
+
"source_config": {
|
|
201
|
+
"database": "postgresql",
|
|
202
|
+
"query": "SELECT * FROM users"
|
|
203
|
+
},
|
|
204
|
+
"destination_config": {
|
|
205
|
+
"type": "snowflake_stage",
|
|
206
|
+
"stage": "@data_stage/users/"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
### Setup
|
|
214
|
+
```bash
|
|
215
|
+
git clone https://github.com/snowflakedb/migrations-data-validation.git
|
|
216
|
+
cd migrations-data-validation/data-exchange-agent
|
|
217
|
+
pip install -e .[development]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Testing
|
|
221
|
+
```bash
|
|
222
|
+
# Run all tests
|
|
223
|
+
pytest
|
|
224
|
+
|
|
225
|
+
# With coverage
|
|
226
|
+
pytest --cov=src/data_exchange_agent
|
|
227
|
+
|
|
228
|
+
# Run specific test types
|
|
229
|
+
pytest tests/unit/ # Unit tests only
|
|
230
|
+
pytest -m "not integration" # Non-integration tests
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Code Quality
|
|
234
|
+
```bash
|
|
235
|
+
# Format code
|
|
236
|
+
ruff format .
|
|
237
|
+
|
|
238
|
+
# Lint code
|
|
239
|
+
ruff check .
|
|
240
|
+
|
|
241
|
+
# Auto-fix linting issues
|
|
242
|
+
ruff check --fix .
|
|
243
|
+
```
|
|
244
|
+
## 🐳 Docker
|
|
245
|
+
|
|
246
|
+
The Data Exchange Agent can be run in a Docker container with configuration injected via environment variables at runtime.
|
|
247
|
+
|
|
248
|
+
### Building the Image
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
cd data-exchange-agent
|
|
252
|
+
docker build -t data-exchange-agent .
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### How It Works
|
|
256
|
+
|
|
257
|
+
The Dockerfile uses configuration templates that are processed at container startup:
|
|
258
|
+
|
|
259
|
+
1. **`docker-artifacts/configuration.template.toml`** - Agent configuration template
|
|
260
|
+
2. **`docker-artifacts/snowflake.config.template.toml`** - Snowflake connection template
|
|
261
|
+
3. **`docker-artifacts/docker-entrypoint.sh`** - Entrypoint script that uses `envsubst` to substitute environment variables into the templates before starting the agent
|
|
262
|
+
|
|
263
|
+
This approach ensures that sensitive credentials (passwords) are never baked into the Docker image—they are only injected at runtime.
|
|
264
|
+
|
|
265
|
+
### Environment Variables
|
|
266
|
+
|
|
267
|
+
#### Data Source Configuration (Required for database connections)
|
|
268
|
+
|
|
269
|
+
| Variable | Description | Default |
|
|
270
|
+
|----------|-------------|---------|
|
|
271
|
+
| `DATA_SOURCE_USERNAME` | Username for the source database | - |
|
|
272
|
+
| `DATA_SOURCE_PASSWORD` | Password for the source database | - |
|
|
273
|
+
| `DATA_SOURCE_HOST` | Hostname of the source database | - |
|
|
274
|
+
| `DATA_SOURCE_PORT` | Port of the source database | `1433` |
|
|
275
|
+
| `DATA_SOURCE_DATABASE` | Database name on the source | - |
|
|
276
|
+
|
|
277
|
+
#### Snowflake Connection Configuration (Required for Snowflake integration)
|
|
278
|
+
|
|
279
|
+
| Variable | Description | Default |
|
|
280
|
+
|----------|-------------|---------|
|
|
281
|
+
| `SNOWFLAKE_ACCOUNT` | Snowflake account identifier (e.g., `myaccount.us-west-2.aws`) | - |
|
|
282
|
+
| `SNOWFLAKE_USER` | Snowflake username | - |
|
|
283
|
+
| `SNOWFLAKE_PASSWORD` | Snowflake password | - |
|
|
284
|
+
| `SNOWFLAKE_WAREHOUSE` | Snowflake warehouse name | - |
|
|
285
|
+
| `SNOWFLAKE_ROLE` | Snowflake role | - |
|
|
286
|
+
| `SNOWFLAKE_DATABASE` | Default Snowflake database | - |
|
|
287
|
+
| `SNOWFLAKE_SCHEMA` | Default Snowflake schema | - |
|
|
288
|
+
|
|
289
|
+
#### Application Configuration
|
|
290
|
+
|
|
291
|
+
| Variable | Description | Default |
|
|
292
|
+
|----------|-------------|---------|
|
|
293
|
+
| `AGENT_AFFINITY` | Agent affinity label for task routing (required) | - |
|
|
294
|
+
| `WORKER_COUNT` | Number of worker threads | `1` |
|
|
295
|
+
|
|
296
|
+
### Running the Container
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
docker run -p 5000:5000 \
|
|
300
|
+
-e DATA_SOURCE_USERNAME="db_user" \
|
|
301
|
+
-e DATA_SOURCE_PASSWORD="db_password" \
|
|
302
|
+
-e DATA_SOURCE_HOST="db.example.com" \
|
|
303
|
+
-e DATA_SOURCE_PORT="1433" \
|
|
304
|
+
-e DATA_SOURCE_DATABASE="mydb" \
|
|
305
|
+
-e SNOWFLAKE_ACCOUNT="myaccount.us-west-2.aws" \
|
|
306
|
+
-e SNOWFLAKE_USER="snowflake_user" \
|
|
307
|
+
-e SNOWFLAKE_PASSWORD="snowflake_password" \
|
|
308
|
+
-e SNOWFLAKE_WAREHOUSE="COMPUTE_WH" \
|
|
309
|
+
-e SNOWFLAKE_ROLE="DATA_ENGINEER" \
|
|
310
|
+
-e SNOWFLAKE_DATABASE="PROD_DB" \
|
|
311
|
+
-e SNOWFLAKE_SCHEMA="PUBLIC" \
|
|
312
|
+
-e AGENT_AFFINITY="blue" \
|
|
313
|
+
-e WORKER_COUNT="8" \
|
|
314
|
+
data-exchange-agent
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
You can also pass additional arguments to the agent:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
docker run -p 8080:8080 \
|
|
321
|
+
-e DATA_SOURCE_PASSWORD="secret" \
|
|
322
|
+
-e SNOWFLAKE_PASSWORD="secret" \
|
|
323
|
+
# ... other env vars ...
|
|
324
|
+
data-exchange-agent --port 8080 --debug
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Running in Snowpark Container Services (SPCS)
|
|
328
|
+
|
|
329
|
+
When deploying the Data Exchange Agent in [Snowpark Container Services](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/overview), you can use the special `@SPCS_CONNECTION` connection name to automatically use Snowflake-provided credentials.
|
|
330
|
+
|
|
331
|
+
#### How It Works
|
|
332
|
+
|
|
333
|
+
When running in SPCS, Snowflake automatically provides:
|
|
334
|
+
- An **OAuth token** at `/snowflake/session/token`
|
|
335
|
+
- **Environment variables**: `SNOWFLAKE_HOST`, `SNOWFLAKE_ACCOUNT`, `SNOWFLAKE_DATABASE`, `SNOWFLAKE_SCHEMA`
|
|
336
|
+
|
|
337
|
+
The `@SPCS_CONNECTION` feature reads these credentials automatically, so you don't need to configure Snowflake passwords or account details manually.
|
|
338
|
+
|
|
339
|
+
> **Note**: `SNOWFLAKE_WAREHOUSE` is **not** provided by SPCS. You can set it manually via environment variable or use the `QUERY_WAREHOUSE` parameter when creating the service.
|
|
340
|
+
|
|
341
|
+
#### Configuration
|
|
342
|
+
|
|
343
|
+
By default, the Docker image uses `@SPCS_CONNECTION`. No additional Snowflake configuration is needed:
|
|
344
|
+
|
|
345
|
+
```toml
|
|
346
|
+
[task_source.snowflake_stored_procedure]
|
|
347
|
+
connection_name = "@SPCS_CONNECTION"
|
|
348
|
+
|
|
349
|
+
[connections.target.snowflake_connection_name]
|
|
350
|
+
connection_name = "@SPCS_CONNECTION"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### Environment Variables for SPCS
|
|
354
|
+
|
|
355
|
+
| Variable | Description | Default |
|
|
356
|
+
|----------|-------------|---------|
|
|
357
|
+
| `SNOWFLAKE_CONNECTION_NAME` | Connection mode: `@SPCS_CONNECTION` for SPCS credentials, or a named connection from `~/.snowflake/config.toml` | `@SPCS_CONNECTION` |
|
|
358
|
+
| `SNOWFLAKE_WAREHOUSE` | Warehouse for queries (not provided by SPCS, must be set manually) | - |
|
|
359
|
+
|
|
360
|
+
#### Switching to Manual Credentials
|
|
361
|
+
|
|
362
|
+
If you need to use traditional Snowflake credentials instead of SPCS-provided ones (e.g., for testing outside SPCS), set the `SNOWFLAKE_CONNECTION_NAME` environment variable:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# Use a named connection from ~/.snowflake/config.toml
|
|
366
|
+
docker run \
|
|
367
|
+
-e SNOWFLAKE_CONNECTION_NAME="MY_SNOWFLAKE_CONNECTION" \
|
|
368
|
+
-e SNOWFLAKE_ACCOUNT="myaccount.us-west-2.aws" \
|
|
369
|
+
-e SNOWFLAKE_USER="user" \
|
|
370
|
+
-e SNOWFLAKE_PASSWORD="password" \
|
|
371
|
+
# ... other env vars ...
|
|
372
|
+
data-exchange-agent
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### Example SPCS Service Definition
|
|
376
|
+
|
|
377
|
+
```sql
|
|
378
|
+
CREATE SERVICE data_exchange_agent
|
|
379
|
+
IN COMPUTE POOL my_compute_pool
|
|
380
|
+
QUERY_WAREHOUSE = MY_WAREHOUSE
|
|
381
|
+
FROM SPECIFICATION $$
|
|
382
|
+
spec:
|
|
383
|
+
containers:
|
|
384
|
+
- name: agent
|
|
385
|
+
image: /my_db/my_schema/my_repo/data-exchange-agent:latest
|
|
386
|
+
env:
|
|
387
|
+
DATA_SOURCE_HOST: "source-db.example.com"
|
|
388
|
+
DATA_SOURCE_PORT: "1433"
|
|
389
|
+
DATA_SOURCE_DATABASE: "mydb"
|
|
390
|
+
DATA_SOURCE_USERNAME: "user"
|
|
391
|
+
AGENT_AFFINITY: "spcs-agent"
|
|
392
|
+
WORKER_COUNT: "4"
|
|
393
|
+
secrets:
|
|
394
|
+
- snowflakeSecret: my_db_password_secret
|
|
395
|
+
secretKeyRef: password
|
|
396
|
+
envVarName: DATA_SOURCE_PASSWORD
|
|
397
|
+
$$;
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
For more details, see the [Snowflake SPCS documentation](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/spcs-execute-sql).
|
|
401
|
+
|
|
402
|
+
## 🔌 Extending the System
|
|
403
|
+
|
|
404
|
+
### Adding a New Bulk Utility
|
|
405
|
+
|
|
406
|
+
Bulk utilities are command-line tools used to efficiently export data from databases (e.g., BCP for SQL Server). Follow these steps to add a new bulk utility:
|
|
407
|
+
|
|
408
|
+
#### 1. Define the Bulk Utility Type
|
|
409
|
+
|
|
410
|
+
Add your new utility to the `BulkUtilityType` enum in `src/data_exchange_agent/data_sources/bulk_utility_types.py`:
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
class BulkUtilityType(str, Enum):
|
|
414
|
+
BCP = "bcp"
|
|
415
|
+
YOUR_UTILITY = "your_utility_name" # Add this line
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### 2. Create Configuration Class
|
|
419
|
+
|
|
420
|
+
Create a new configuration class in `src/data_exchange_agent/config/sections/bulk_utilities/your_utility.py`:
|
|
421
|
+
|
|
422
|
+
```python
|
|
423
|
+
from data_exchange_agent.config.sections.bulk_utilities.base import BaseBulkUtilityConfig
|
|
424
|
+
|
|
425
|
+
class YourUtilityConfig(BaseBulkUtilityConfig):
|
|
426
|
+
"""Configuration class for YourUtility bulk utility settings."""
|
|
427
|
+
|
|
428
|
+
def __init__(
|
|
429
|
+
self,
|
|
430
|
+
# Add utility-specific parameters
|
|
431
|
+
utility_specific_parameter: str = "default_param",
|
|
432
|
+
) -> None:
|
|
433
|
+
"""Initialize YourUtility configuration."""
|
|
434
|
+
self.utility_specific_parameter = utility_specific_parameter
|
|
435
|
+
|
|
436
|
+
def _custom_validation(self) -> str | None:
|
|
437
|
+
"""Validate configuration parameters."""
|
|
438
|
+
if not self.utility_specific_parameter:
|
|
439
|
+
return "Utility specific parameter cannot be empty."
|
|
440
|
+
return None
|
|
441
|
+
|
|
442
|
+
def __repr__(self) -> str:
|
|
443
|
+
"""Return string representation."""
|
|
444
|
+
return f"YourUtilityConfig(utility_specific_parameter='{self.utility_specific_parameter}')"
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### 3. Register the Bulk Utility
|
|
448
|
+
|
|
449
|
+
Register your utility in `src/data_exchange_agent/config/sections/bulk_utilities/__init__.py`:
|
|
450
|
+
|
|
451
|
+
```python
|
|
452
|
+
from data_exchange_agent.config.sections.bulk_utilities.your_utility import YourUtilityConfig
|
|
453
|
+
from data_exchange_agent.constants.connection_types import ConnectionType
|
|
454
|
+
|
|
455
|
+
# Add to registry
|
|
456
|
+
BulkUtilityRegistry.register(ConnectionType.YOUR_UTILITY, YourUtilityConfig) # Add this
|
|
457
|
+
|
|
458
|
+
# Add to __all__
|
|
459
|
+
__all__ = [
|
|
460
|
+
"BaseBulkUtilityConfig",
|
|
461
|
+
"BulkUtilityRegistry",
|
|
462
|
+
"BCPBulkUtilityConfig",
|
|
463
|
+
"YourUtilityConfig", # Add this
|
|
464
|
+
]
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### 4. Update ConnectionType Enum
|
|
468
|
+
|
|
469
|
+
Add your utility type to `src/data_exchange_agent/constants/connection_types.py`:
|
|
470
|
+
|
|
471
|
+
```python
|
|
472
|
+
class ConnectionType(str, Enum):
|
|
473
|
+
# Bulk utilities
|
|
474
|
+
BCP = BulkUtilityType.BCP.value
|
|
475
|
+
YOUR_UTILITY = BulkUtilityType.YOUR_UTILITY.value # Add this
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
#### 5. Create Data Source Implementation
|
|
479
|
+
|
|
480
|
+
Create the data source class in `src/data_exchange_agent/data_sources/your_utility_data_source.py`:
|
|
481
|
+
|
|
482
|
+
```python
|
|
483
|
+
from data_exchange_agent.data_sources.base import BaseDataSource
|
|
484
|
+
from data_exchange_agent.data_sources.bulk_utility_types import BulkUtilityType
|
|
485
|
+
|
|
486
|
+
class YourUtilityDataSource(BaseDataSource):
|
|
487
|
+
"""Data source implementation for YourUtility."""
|
|
488
|
+
|
|
489
|
+
@inject
|
|
490
|
+
def __init__(
|
|
491
|
+
self,
|
|
492
|
+
engine: str,
|
|
493
|
+
statement: str,
|
|
494
|
+
results_folder_path: str = None,
|
|
495
|
+
base_file_name: str = "result",
|
|
496
|
+
logger: SFLogger = Provide[container_keys.SF_LOGGER],
|
|
497
|
+
program_config: ConfigManager = Provide[container_keys.PROGRAM_CONFIG],
|
|
498
|
+
) -> None:
|
|
499
|
+
"""Initialize YourUtilityDataSource."""
|
|
500
|
+
self.logger = logger
|
|
501
|
+
self._statement = statement
|
|
502
|
+
|
|
503
|
+
# Get configuration
|
|
504
|
+
bulk_utility_config = program_config[config_keys.BULK_UTILITY]
|
|
505
|
+
utility_config = bulk_utility_config.get(BulkUtilityType.YOUR_UTILITY, None)
|
|
506
|
+
|
|
507
|
+
# Use config values or defaults
|
|
508
|
+
self.utility_specific_parameter = utility_config.utility_specific_parameter if utility_config else "default_param"
|
|
509
|
+
|
|
510
|
+
def export_data(self) -> bool:
|
|
511
|
+
"""Export data using your utility command."""
|
|
512
|
+
# Implement the export logic
|
|
513
|
+
pass
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
#### 6. Add Configuration to TOML
|
|
517
|
+
|
|
518
|
+
Users can now configure your bulk utility in `configuration.toml`:
|
|
519
|
+
|
|
520
|
+
```toml
|
|
521
|
+
[bulk_utility.your_utility_name]
|
|
522
|
+
# Add your custom parameters
|
|
523
|
+
utility_specific_parameter = "param"
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
#### 7. Write Tests
|
|
527
|
+
|
|
528
|
+
Create tests in `tests/data_sources/test_your_utility_data_source.py` to verify functionality.
|
|
529
|
+
|
|
530
|
+
### Example: BCP Implementation
|
|
531
|
+
|
|
532
|
+
See the existing BCP implementation for reference:
|
|
533
|
+
- Config: `src/data_exchange_agent/config/sections/bulk_utilities/bcp.py`
|
|
534
|
+
- Data Source: `src/data_exchange_agent/data_sources/bcp_data_source.py`
|
|
535
|
+
- Configuration example in `configuration_example.toml`
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## 🤝 Contributing
|
|
540
|
+
|
|
541
|
+
We welcome contributions! See our [Contributing Guide](../CONTRIBUTING.md) for details on how to collaborate, set up your development environment, and submit PRs.
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## 📄 License
|
|
546
|
+
|
|
547
|
+
This project is licensed under the Apache License 2.0. See the [LICENSE](../LICENSE) file for details.
|
|
548
|
+
|
|
549
|
+
## 🆘 Support
|
|
550
|
+
|
|
551
|
+
- **Documentation**: [Full documentation](https://github.com/snowflakedb/migrations-data-validation)
|
|
552
|
+
- **Issues**: [GitHub Issues](https://github.com/snowflakedb/migrations-data-validation/issues)
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
**Developed with ❄️ by Snowflake**
|