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.
Files changed (47) hide show
  1. {table_validator-0.1.2/table_validator.egg-info → table_validator-0.1.3}/PKG-INFO +9 -1
  2. {table_validator-0.1.2 → table_validator-0.1.3}/README.md +8 -0
  3. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/databricks_connector.py +29 -5
  4. {table_validator-0.1.2 → table_validator-0.1.3/table_validator.egg-info}/PKG-INFO +9 -1
  5. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/scm_version.json +2 -2
  6. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_databricks_connector.py +78 -0
  7. {table_validator-0.1.2 → table_validator-0.1.3}/LICENSE +0 -0
  8. {table_validator-0.1.2 → table_validator-0.1.3}/pyproject.toml +0 -0
  9. {table_validator-0.1.2 → table_validator-0.1.3}/setup.cfg +0 -0
  10. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/__init__.py +0 -0
  11. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/auth/__init__.py +0 -0
  12. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/auth/azure_auth.py +0 -0
  13. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/auth/databricks_auth.py +0 -0
  14. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/__init__.py +0 -0
  15. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/main.py +0 -0
  16. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/partition_prompt.py +0 -0
  17. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/summary_table.py +0 -0
  18. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/cli/wizard.py +0 -0
  19. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/config/__init__.py +0 -0
  20. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/config/manager.py +0 -0
  21. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/config/schema.py +0 -0
  22. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/__init__.py +0 -0
  23. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/connectors/azure_connector.py +0 -0
  24. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/engine/__init__.py +0 -0
  25. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/engine/comparison_engine.py +0 -0
  26. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/models.py +0 -0
  27. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/reports/__init__.py +0 -0
  28. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/reports/excel_report.py +0 -0
  29. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/__init__.py +0 -0
  30. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/blob_discovery.py +0 -0
  31. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/catalog_validator.py +0 -0
  32. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator/validators/row_validator.py +0 -0
  33. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/SOURCES.txt +0 -0
  34. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/dependency_links.txt +0 -0
  35. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/entry_points.txt +0 -0
  36. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/requires.txt +0 -0
  37. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/scm_file_list.json +0 -0
  38. {table_validator-0.1.2 → table_validator-0.1.3}/table_validator.egg-info/top_level.txt +0 -0
  39. {table_validator-0.1.2 → table_validator-0.1.3}/tests/__init__.py +0 -0
  40. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_blob_discovery.py +0 -0
  41. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_catalog_validator.py +0 -0
  42. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_cli.py +0 -0
  43. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_excel_report.py +0 -0
  44. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_partition_prompt.py +0 -0
  45. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_report_command.py +0 -0
  46. {table_validator-0.1.2 → table_validator-0.1.3}/tests/test_row_validator.py +0 -0
  47. {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.2
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.
@@ -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
- self._connection = sql.connect(
142
- server_hostname=self._host,
143
- http_path=self._http_path,
144
- access_token=self._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.2
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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.1.2",
2
+ "tag": "0.1.3",
3
3
  "distance": 0,
4
- "node": "g43988f9f51a097e239c49384ab59f00fec5851ab",
4
+ "node": "g8f7a326158b935508f39bc9369245d7817f1dc89",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-27"
@@ -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