table-validator 0.1.2__tar.gz → 0.1.3__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.
- {table_validator-0.1.2/table_validator.egg-info → table_validator-0.1.3}/PKG-INFO +9 -1
- {table_validator-0.1.2 → table_validator-0.1.3}/README.md +8 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/databricks_connector.py +29 -5
- {table_validator-0.1.2 → table_validator-0.1.3/table_validator.egg-info}/PKG-INFO +9 -1
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/scm_version.json +2 -2
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_databricks_connector.py +78 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/LICENSE +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/pyproject.toml +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/setup.cfg +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/auth/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/auth/azure_auth.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/auth/databricks_auth.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/main.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/partition_prompt.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/summary_table.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/wizard.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/config/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/config/manager.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/config/schema.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/azure_connector.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/engine/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/engine/comparison_engine.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/models.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/reports/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/reports/excel_report.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/blob_discovery.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/catalog_validator.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/row_validator.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/SOURCES.txt +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/dependency_links.txt +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/entry_points.txt +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/requires.txt +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/scm_file_list.json +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/top_level.txt +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/__init__.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_blob_discovery.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_catalog_validator.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_cli.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_excel_report.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_partition_prompt.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_report_command.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_row_validator.py +0 -0
- {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_wizard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: table-validator
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: CLI tool for validating data migrations between Azure (Blob Storage / SQL Database) and Databricks Delta Lake catalogs
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -174,6 +174,14 @@ Everything lives outside the repo, under your home directory:
|
|
|
174
174
|
by construction, since it's written under your home directory rather
|
|
175
175
|
than the working directory.
|
|
176
176
|
|
|
177
|
+
Optional: `DATABRICKS_RETRY_TIMEOUT_SECONDS` (a plain environment variable,
|
|
178
|
+
not part of `config.yaml`) raises the CloudFetch HTTP retry timeout above
|
|
179
|
+
its 300-second default. On a slow or unstable network, downloading a
|
|
180
|
+
large row-hash result set can legitimately take longer than that, causing
|
|
181
|
+
a `Retry request would exceed Retry policy max retry duration` failure
|
|
182
|
+
even though the query itself succeeded. Set it higher (e.g. `900` for 15
|
|
183
|
+
minutes) if you hit this on large tables.
|
|
184
|
+
|
|
177
185
|
A future version will replace manual credential entry with Azure CLI /
|
|
178
186
|
Service Principal auth and Databricks CLI / OAuth login, without changing
|
|
179
187
|
the config file format or any command usage above.
|
|
@@ -147,6 +147,14 @@ Everything lives outside the repo, under your home directory:
|
|
|
147
147
|
by construction, since it's written under your home directory rather
|
|
148
148
|
than the working directory.
|
|
149
149
|
|
|
150
|
+
Optional: `DATABRICKS_RETRY_TIMEOUT_SECONDS` (a plain environment variable,
|
|
151
|
+
not part of `config.yaml`) raises the CloudFetch HTTP retry timeout above
|
|
152
|
+
its 300-second default. On a slow or unstable network, downloading a
|
|
153
|
+
large row-hash result set can legitimately take longer than that, causing
|
|
154
|
+
a `Retry request would exceed Retry policy max retry duration` failure
|
|
155
|
+
even though the query itself succeeded. Set it higher (e.g. `900` for 15
|
|
156
|
+
minutes) if you hit this on large tables.
|
|
157
|
+
|
|
150
158
|
A future version will replace manual credential entry with Azure CLI /
|
|
151
159
|
Service Principal auth and Databricks CLI / OAuth login, without changing
|
|
152
160
|
the config file format or any command usage above.
|
{table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/databricks_connector.py
RENAMED
|
@@ -14,6 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
import datetime
|
|
15
15
|
import logging
|
|
16
16
|
import numbers
|
|
17
|
+
import os
|
|
17
18
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple
|
|
18
19
|
|
|
19
20
|
import pandas as pd
|
|
@@ -97,6 +98,7 @@ class DatabricksConnector:
|
|
|
97
98
|
host: Optional[str] = None,
|
|
98
99
|
token: Optional[str] = None,
|
|
99
100
|
http_path: Optional[str] = None,
|
|
101
|
+
retry_timeout_seconds: Optional[float] = None,
|
|
100
102
|
) -> None:
|
|
101
103
|
"""
|
|
102
104
|
host/token/http_path must be resolved by the caller before
|
|
@@ -104,11 +106,27 @@ class DatabricksConnector:
|
|
|
104
106
|
get_databricks_token() for the token, and config.databricks.
|
|
105
107
|
workspace_url/http_path for the rest. This connector does not
|
|
106
108
|
read credentials from the environment itself.
|
|
109
|
+
|
|
110
|
+
retry_timeout_seconds overrides databricks-sql-connector's
|
|
111
|
+
CloudFetch HTTP retry policy (_retry_stop_after_attempts_duration),
|
|
112
|
+
which otherwise defaults to 300 seconds. On a slow or unstable
|
|
113
|
+
network, downloading a large row-hash result set can legitimately
|
|
114
|
+
take longer than that, causing a hard
|
|
115
|
+
"Retry request would exceed Retry policy max retry duration"
|
|
116
|
+
failure even though the query itself succeeded - raising this
|
|
117
|
+
gives a slow-but-working connection more time instead of giving
|
|
118
|
+
up. Falls back to the DATABRICKS_RETRY_TIMEOUT_SECONDS environment
|
|
119
|
+
variable, then the connector's own default, if not given.
|
|
107
120
|
"""
|
|
108
121
|
|
|
109
122
|
self._host = host
|
|
110
123
|
self._token = token
|
|
111
124
|
self._http_path = http_path
|
|
125
|
+
self._retry_timeout_seconds = retry_timeout_seconds or (
|
|
126
|
+
float(os.environ["DATABRICKS_RETRY_TIMEOUT_SECONDS"])
|
|
127
|
+
if os.environ.get("DATABRICKS_RETRY_TIMEOUT_SECONDS")
|
|
128
|
+
else None
|
|
129
|
+
)
|
|
112
130
|
|
|
113
131
|
if not self._host or not self._token:
|
|
114
132
|
raise ValueError(
|
|
@@ -138,11 +156,17 @@ class DatabricksConnector:
|
|
|
138
156
|
|
|
139
157
|
try:
|
|
140
158
|
|
|
141
|
-
|
|
142
|
-
server_hostname
|
|
143
|
-
http_path
|
|
144
|
-
access_token
|
|
145
|
-
|
|
159
|
+
connect_kwargs: Dict[str, Any] = {
|
|
160
|
+
"server_hostname": self._host,
|
|
161
|
+
"http_path": self._http_path,
|
|
162
|
+
"access_token": self._token,
|
|
163
|
+
}
|
|
164
|
+
if self._retry_timeout_seconds is not None:
|
|
165
|
+
connect_kwargs["_retry_stop_after_attempts_duration"] = (
|
|
166
|
+
self._retry_timeout_seconds
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
self._connection = sql.connect(**connect_kwargs)
|
|
146
170
|
|
|
147
171
|
with self._connection.cursor() as cursor:
|
|
148
172
|
cursor.execute("SELECT 1")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: table-validator
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: CLI tool for validating data migrations between Azure (Blob Storage / SQL Database) and Databricks Delta Lake catalogs
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -174,6 +174,14 @@ Everything lives outside the repo, under your home directory:
|
|
|
174
174
|
by construction, since it's written under your home directory rather
|
|
175
175
|
than the working directory.
|
|
176
176
|
|
|
177
|
+
Optional: `DATABRICKS_RETRY_TIMEOUT_SECONDS` (a plain environment variable,
|
|
178
|
+
not part of `config.yaml`) raises the CloudFetch HTTP retry timeout above
|
|
179
|
+
its 300-second default. On a slow or unstable network, downloading a
|
|
180
|
+
large row-hash result set can legitimately take longer than that, causing
|
|
181
|
+
a `Retry request would exceed Retry policy max retry duration` failure
|
|
182
|
+
even though the query itself succeeded. Set it higher (e.g. `900` for 15
|
|
183
|
+
minutes) if you hit this on large tables.
|
|
184
|
+
|
|
177
185
|
A future version will replace manual credential entry with Azure CLI /
|
|
178
186
|
Service Principal auth and Databricks CLI / OAuth login, without changing
|
|
179
187
|
the config file format or any command usage above.
|
|
@@ -8,9 +8,12 @@ so these tests verify SQL-generation logic and result parsing only.
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
from unittest.mock import MagicMock
|
|
12
|
+
|
|
11
13
|
import pandas as pd
|
|
12
14
|
import pytest
|
|
13
15
|
|
|
16
|
+
import table_validator.connectors.databricks_connector as databricks_connector_module
|
|
14
17
|
from table_validator.connectors.databricks_connector import DatabricksConnector
|
|
15
18
|
|
|
16
19
|
|
|
@@ -402,3 +405,78 @@ def test_get_row_detail_for_row_numbers_wraps_exceptions(monkeypatch):
|
|
|
402
405
|
row_numbers=[2],
|
|
403
406
|
value_columns=["id"],
|
|
404
407
|
)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
# ---------------------------------------------------------------------------
|
|
411
|
+
# connect(): retry timeout override for slow/unstable CloudFetch downloads.
|
|
412
|
+
# ---------------------------------------------------------------------------
|
|
413
|
+
def test_connect_omits_retry_kwarg_by_default(monkeypatch):
|
|
414
|
+
"""Without an explicit retry_timeout_seconds or
|
|
415
|
+
DATABRICKS_RETRY_TIMEOUT_SECONDS, connect() must not pass
|
|
416
|
+
_retry_stop_after_attempts_duration at all, preserving
|
|
417
|
+
databricks-sql-connector's own default (300s)."""
|
|
418
|
+
monkeypatch.delenv("DATABRICKS_RETRY_TIMEOUT_SECONDS", raising=False)
|
|
419
|
+
captured = {}
|
|
420
|
+
|
|
421
|
+
def fake_connect(**kwargs):
|
|
422
|
+
captured.update(kwargs)
|
|
423
|
+
return MagicMock()
|
|
424
|
+
|
|
425
|
+
monkeypatch.setattr(databricks_connector_module.sql, "connect", fake_connect)
|
|
426
|
+
connector = _connector()
|
|
427
|
+
|
|
428
|
+
connector.connect()
|
|
429
|
+
|
|
430
|
+
assert "_retry_stop_after_attempts_duration" not in captured
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def test_connect_passes_explicit_retry_timeout_seconds(monkeypatch):
|
|
434
|
+
monkeypatch.delenv("DATABRICKS_RETRY_TIMEOUT_SECONDS", raising=False)
|
|
435
|
+
captured = {}
|
|
436
|
+
|
|
437
|
+
def fake_connect(**kwargs):
|
|
438
|
+
captured.update(kwargs)
|
|
439
|
+
return MagicMock()
|
|
440
|
+
|
|
441
|
+
monkeypatch.setattr(databricks_connector_module.sql, "connect", fake_connect)
|
|
442
|
+
connector = DatabricksConnector(
|
|
443
|
+
host="h", token="t", http_path="p", retry_timeout_seconds=900.0
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
connector.connect()
|
|
447
|
+
|
|
448
|
+
assert captured["_retry_stop_after_attempts_duration"] == 900.0
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def test_connect_falls_back_to_retry_timeout_env_var(monkeypatch):
|
|
452
|
+
monkeypatch.setenv("DATABRICKS_RETRY_TIMEOUT_SECONDS", "1200")
|
|
453
|
+
captured = {}
|
|
454
|
+
|
|
455
|
+
def fake_connect(**kwargs):
|
|
456
|
+
captured.update(kwargs)
|
|
457
|
+
return MagicMock()
|
|
458
|
+
|
|
459
|
+
monkeypatch.setattr(databricks_connector_module.sql, "connect", fake_connect)
|
|
460
|
+
connector = _connector()
|
|
461
|
+
|
|
462
|
+
connector.connect()
|
|
463
|
+
|
|
464
|
+
assert captured["_retry_stop_after_attempts_duration"] == 1200.0
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def test_connect_explicit_arg_takes_priority_over_env_var(monkeypatch):
|
|
468
|
+
monkeypatch.setenv("DATABRICKS_RETRY_TIMEOUT_SECONDS", "1200")
|
|
469
|
+
captured = {}
|
|
470
|
+
|
|
471
|
+
def fake_connect(**kwargs):
|
|
472
|
+
captured.update(kwargs)
|
|
473
|
+
return MagicMock()
|
|
474
|
+
|
|
475
|
+
monkeypatch.setattr(databricks_connector_module.sql, "connect", fake_connect)
|
|
476
|
+
connector = DatabricksConnector(
|
|
477
|
+
host="h", token="t", http_path="p", retry_timeout_seconds=600.0
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
connector.connect()
|
|
481
|
+
|
|
482
|
+
assert captured["_retry_stop_after_attempts_duration"] == 600.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/azure_connector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/blob_discovery.py
RENAMED
|
File without changes
|
{table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/catalog_validator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|