Skip to content

Commit 4e5af9e

Browse files
authored
Merge pull request #8 from jiatolentino/DM-3293-databricks-support
feat: Add databricks to DatabaseType enum
2 parents a79c17d + d9d3760 commit 4e5af9e

7 files changed

Lines changed: 84 additions & 53 deletions

File tree

HISTORY.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
History
33
=======
44

5+
1.0.3 (2026-05-27)
6+
------------------
7+
8+
* Added ``databricks`` to ``DatabaseType`` enum.
9+
* Removed ``DatabricksDeltaS3ConnectionConfig``.
10+
511
1.0.2 (2026-05-14)
612
------------------
713

datamasque/client/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
ConnectionId,
3131
DatabaseConnectionConfig,
3232
DatabaseType,
33-
DatabricksDeltaS3ConnectionConfig,
33+
DatabricksConnectionConfig,
3434
DynamoConnectionConfig,
3535
FileConnectionConfig,
3636
MongoConnectionConfig,
@@ -129,7 +129,7 @@
129129
"DataMasqueUserError",
130130
"DatabaseConnectionConfig",
131131
"DatabaseType",
132-
"DatabricksDeltaS3ConnectionConfig",
132+
"DatabricksConnectionConfig",
133133
"DiscoveryMatch",
134134
"DynamoConnectionConfig",
135135
"FailedToStartError",

datamasque/client/models/connection.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class DatabaseType(Enum):
4545
snowflake = "snowflake"
4646
mongodb = "mongodb"
4747
databricks_lakebase = "databricks_lakebase"
48+
databricks = "databricks"
4849

4950

5051
class SnowflakeStageLocation(str, Enum):
@@ -280,6 +281,8 @@ def _reject_special_engines(self) -> "DatabaseConnectionConfig":
280281
raise ValueError("For Snowflake, use the SnowflakeConnectionConfig class instead")
281282
if self.database_type is DatabaseType.mongodb:
282283
raise ValueError("For MongoDB, use the MongoConnectionConfig class instead")
284+
if self.database_type is DatabaseType.databricks:
285+
raise ValueError("For Databricks SQL Warehouse, use the DatabricksConnectionConfig class instead")
283286
return self
284287

285288
mask_type: Literal["database"] = "database"
@@ -391,26 +394,44 @@ class MountedShareConnectionConfig(FileConnectionConfig):
391394
type: Literal["mounted_share_connection"] = "mounted_share_connection"
392395

393396

394-
class DatabricksDeltaS3ConnectionConfig(FileConnectionConfig):
395-
"""Connection configuration for Databricks Delta tables stored in S3."""
397+
class DatabricksConnectionConfig(ConnectionConfig):
398+
"""Connection configuration for a Databricks SQL Warehouse."""
396399

397-
type: Literal["databricks_delta_s3_connection"] = "databricks_delta_s3_connection"
398-
bucket: str = ""
399-
iam_role_arn: Optional[str] = None
400+
server_hostname: str
401+
http_path: str
402+
access_token: Optional[str] = None
403+
catalog: str
404+
db_schema: Optional[str] = Field(default=None, alias="schema")
405+
is_read_only: bool = False
406+
version: str = "1.0"
407+
408+
mask_type: Literal["database"] = "database"
409+
db_type: Literal["databricks"] = "databricks"
410+
411+
@property
412+
def database_type(self) -> DatabaseType:
413+
return DatabaseType.databricks
414+
415+
@model_validator(mode="before")
416+
@classmethod
417+
def _strip_encrypted_token(cls, data: dict) -> dict:
418+
if isinstance(data, dict):
419+
data.pop("access_token_encrypted", None)
420+
return data
400421

401422

402423
FILE_TYPE_MAP: dict[str, type[FileConnectionConfig]] = {
403424
"s3_connection": S3ConnectionConfig,
404425
"azure_blob_connection": AzureConnectionConfig,
405426
"mounted_share_connection": MountedShareConnectionConfig,
406-
"databricks_delta_s3_connection": DatabricksDeltaS3ConnectionConfig,
407427
}
408428

409429
DB_TYPE_MAP: dict[str, type[ConnectionConfig]] = {
410430
DatabaseType.dynamodb.value: DynamoConnectionConfig,
411431
DatabaseType.mongodb.value: MongoConnectionConfig,
412432
DatabaseType.snowflake.value: SnowflakeConnectionConfig,
413433
DatabaseType.mssql_linked.value: MssqlLinkedServerConnectionConfig,
434+
DatabaseType.databricks.value: DatabricksConnectionConfig,
414435
# others use the default `DatabaseConnectionConfig`
415436
}
416437

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "datamasque-python"
3-
version = "1.0.2"
3+
version = "1.0.3"
44
description = "Official Python client for the DataMasque data-masking API."
55
authors = [
66
{ name = "DataMasque Ltd" },

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.0.2
2+
current_version = 1.0.3
33
commit = True
44
tag = True
55

tests/test_connections.py

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
ConnectionId,
1010
DatabaseConnectionConfig,
1111
DatabaseType,
12-
DatabricksDeltaS3ConnectionConfig,
12+
DatabricksConnectionConfig,
1313
DynamoConnectionConfig,
1414
MongoConnectionConfig,
1515
MountedShareConnectionConfig,
@@ -696,63 +696,67 @@ def test_s3_connection_model_validate_no_iam_role():
696696
assert conn.iam_role_arn is None
697697

698698

699-
def test_databricks_delta_s3_connection_model_validate():
699+
def test_databricks_connection_model_validate():
700700
payload = {
701-
"id": "11223344-5566-7788-99aa-bbccddeeff00",
702-
"name": "delta_s3",
703-
"mask_type": "file",
704-
"type": "databricks_delta_s3_connection",
705-
"base_directory": "delta/",
706-
"is_file_mask_source": True,
707-
"is_file_mask_destination": False,
708-
"bucket": "my-delta-bucket",
709-
"iam_role_arn": "arn:aws:iam::111122223333:role/delta-role",
701+
"id": "db-id-1",
702+
"name": "databricks",
703+
"mask_type": "database",
704+
"db_type": "databricks",
705+
"server_hostname": "adb-1234.azuredatabricks.net",
706+
"http_path": "/sql/1.0/warehouses/abcd1234",
707+
"access_token": "dapi1234",
708+
"catalog": "main",
709+
"schema": "default",
710+
"is_read_only": False,
710711
}
711712

712-
conn = DatabricksDeltaS3ConnectionConfig.model_validate(payload)
713+
conn = DatabricksConnectionConfig.model_validate(payload)
713714

714-
assert isinstance(conn, DatabricksDeltaS3ConnectionConfig)
715-
assert conn.id == "11223344-5566-7788-99aa-bbccddeeff00"
716-
assert conn.name == "delta_s3"
717-
assert conn.bucket == "my-delta-bucket"
718-
assert conn.base_directory == "delta/"
719-
assert conn.is_file_mask_source is True
720-
assert conn.is_file_mask_destination is False
721-
assert conn.iam_role_arn == "arn:aws:iam::111122223333:role/delta-role"
715+
assert isinstance(conn, DatabricksConnectionConfig)
716+
assert conn.id == "db-id-1"
717+
assert conn.server_hostname == "adb-1234.azuredatabricks.net"
718+
assert conn.http_path == "/sql/1.0/warehouses/abcd1234"
719+
assert conn.access_token == "dapi1234"
720+
assert conn.catalog == "main"
721+
assert conn.db_schema == "default"
722+
assert conn.database_type is DatabaseType.databricks
722723

723724

724-
def test_databricks_delta_s3_connection_model_validate_no_iam_role():
725+
def test_databricks_connection_model_validate_blanks_encrypted_token():
725726
payload = {
726-
"id": "id-delta",
727-
"name": "delta_s3",
728-
"mask_type": "file",
729-
"type": "databricks_delta_s3_connection",
730-
"base_directory": "",
731-
"is_file_mask_source": True,
732-
"is_file_mask_destination": False,
733-
"bucket": "my-delta-bucket",
727+
"id": "db-id-2",
728+
"name": "databricks",
729+
"mask_type": "database",
730+
"db_type": "databricks",
731+
"server_hostname": "adb-1234.azuredatabricks.net",
732+
"http_path": "/sql/1.0/warehouses/abcd1234",
733+
"access_token_encrypted": "some_base64_here",
734+
"catalog": "main",
735+
"is_read_only": False,
734736
}
735737

736-
conn = DatabricksDeltaS3ConnectionConfig.model_validate(payload)
737-
assert conn.iam_role_arn is None
738+
conn = DatabricksConnectionConfig.model_validate(payload)
739+
740+
assert isinstance(conn, DatabricksConnectionConfig)
741+
assert conn.access_token is None
738742

739743

740-
def test_validate_connection_dispatches_databricks_delta_s3():
744+
def test_validate_connection_dispatches_databricks():
741745
payload = {
742-
"id": "aabb-ccdd",
743-
"name": "delta",
744-
"mask_type": "file",
745-
"type": "databricks_delta_s3_connection",
746-
"base_directory": "",
747-
"is_file_mask_source": False,
748-
"is_file_mask_destination": True,
749-
"bucket": "delta-bucket",
746+
"id": "db-id-3",
747+
"name": "databricks",
748+
"mask_type": "database",
749+
"db_type": "databricks",
750+
"server_hostname": "adb-1234.azuredatabricks.net",
751+
"http_path": "/sql/1.0/warehouses/abcd1234",
752+
"catalog": "main",
753+
"is_read_only": False,
750754
}
751755

752756
conn = validate_connection(payload)
753757

754-
assert isinstance(conn, DatabricksDeltaS3ConnectionConfig)
755-
assert conn.bucket == "delta-bucket"
758+
assert isinstance(conn, DatabricksConnectionConfig)
759+
assert conn.catalog == "main"
756760

757761

758762
def test_azure_connection_model_validate_blanks_encrypted_connection_string():

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)