datamasque-python 1.2.3__tar.gz → 1.2.5__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 (90) hide show
  1. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/HISTORY.rst +16 -0
  2. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/PKG-INFO +1 -1
  3. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/connection.py +23 -0
  4. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/status.py +1 -0
  5. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/pyproject.toml +1 -1
  6. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_connections.py +83 -0
  7. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/uv.lock +1 -1
  8. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/.editorconfig +0 -0
  9. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/.github/workflows/ci.yml +0 -0
  10. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/.github/workflows/release-testpypi.yml +0 -0
  11. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/.github/workflows/release.yml +0 -0
  12. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/.gitignore +0 -0
  13. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/.readthedocs.yaml +0 -0
  14. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/CONTRIBUTING.rst +0 -0
  15. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/LICENSE +0 -0
  16. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/MANIFEST.in +0 -0
  17. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/Makefile +0 -0
  18. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/NOTICE +0 -0
  19. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/README.rst +0 -0
  20. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/RELEASING.rst +0 -0
  21. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/__init__.py +0 -0
  22. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/base.py +0 -0
  23. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/connections.py +0 -0
  24. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/discovery.py +0 -0
  25. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/discovery_config_libraries.py +0 -0
  26. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/discovery_configs.py +0 -0
  27. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/dmclient.py +0 -0
  28. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/exceptions.py +0 -0
  29. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/files.py +0 -0
  30. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/ifm.py +0 -0
  31. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/license.py +0 -0
  32. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/__init__.py +0 -0
  33. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/data_selection.py +0 -0
  34. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/discovery.py +0 -0
  35. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/discovery_config.py +0 -0
  36. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/discovery_config_library.py +0 -0
  37. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/dm_instance.py +0 -0
  38. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/files.py +0 -0
  39. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/git.py +0 -0
  40. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/ifm.py +0 -0
  41. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/license.py +0 -0
  42. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/pagination.py +0 -0
  43. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/rg_config.py +0 -0
  44. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/ruleset.py +0 -0
  45. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/ruleset_library.py +0 -0
  46. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/runs.py +0 -0
  47. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/safe_data_preview.py +0 -0
  48. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/table_reference.py +0 -0
  49. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/models/user.py +0 -0
  50. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/py.typed +0 -0
  51. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/rg_configs.py +0 -0
  52. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/ruleset_libraries.py +0 -0
  53. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/rulesets.py +0 -0
  54. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/runs.py +0 -0
  55. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/settings.py +0 -0
  56. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/spcs.py +0 -0
  57. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/table_references.py +0 -0
  58. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/datamasque/client/users.py +0 -0
  59. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/Makefile +0 -0
  60. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/client.models.rst +0 -0
  61. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/client.rst +0 -0
  62. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/conf.py +0 -0
  63. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/contributing.rst +0 -0
  64. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/history.rst +0 -0
  65. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/index.rst +0 -0
  66. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/installation.rst +0 -0
  67. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/make.bat +0 -0
  68. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/modules.rst +0 -0
  69. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/readme.rst +0 -0
  70. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/docs/usage.rst +0 -0
  71. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/__init__.py +0 -0
  72. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/conftest.py +0 -0
  73. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/helpers.py +0 -0
  74. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_base.py +0 -0
  75. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_discovery.py +0 -0
  76. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_discovery_config_libraries.py +0 -0
  77. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_discovery_configs.py +0 -0
  78. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_files.py +0 -0
  79. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_ifm.py +0 -0
  80. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_license.py +0 -0
  81. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_pagination.py +0 -0
  82. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_rg_configs.py +0 -0
  83. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_ruleset_library.py +0 -0
  84. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_rulesets.py +0 -0
  85. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_runs.py +0 -0
  86. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_safe_data_preview.py +0 -0
  87. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_settings.py +0 -0
  88. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_spcs.py +0 -0
  89. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_table_references.py +0 -0
  90. {datamasque_python-1.2.3 → datamasque_python-1.2.5}/tests/test_users.py +0 -0
@@ -2,6 +2,22 @@
2
2
  History
3
3
  =======
4
4
 
5
+ 1.2.5 (2026-08-17)
6
+ ------------------
7
+
8
+ * Added ``iam_role_arn`` to ``DatabaseConnectionConfig``: the IAM role DataMasque assumes to tag
9
+ the connection's AWS resource, for resources in another AWS account. Sent only for the engines
10
+ that can be an Amazon RDS instance, Aurora cluster or Redshift cluster.
11
+
12
+ Requires server version 3.26.16
13
+
14
+ 1.2.4 (2026-08-12)
15
+ ------------------
16
+
17
+ * Added ``rg_config`` to ``ValidationErrorType``, covering ruleset generation config validation errors.
18
+
19
+ Requires server version 3.26.15
20
+
5
21
  1.2.3 (2026-08-12)
6
22
  ------------------
7
23
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: datamasque-python
3
- Version: 1.2.3
3
+ Version: 1.2.5
4
4
  Summary: Official Python client for the DataMasque data-masking API.
5
5
  Project-URL: Homepage, https://datamasque.com/
6
6
  Project-URL: Documentation, https://datamasque-python.readthedocs.io/
@@ -289,6 +289,22 @@ class SnowflakeConnectionConfig(ConnectionConfig):
289
289
  return data
290
290
 
291
291
 
292
+ # Engines that can sit behind an Amazon RDS, Aurora or Redshift endpoint, and so can carry a role
293
+ # for DataMasque to assume when tagging the resource. Aurora needs no entry of its own: it uses
294
+ # these same engines with a cluster endpoint.
295
+ _AWS_TAGGABLE_DATABASE_TYPES = frozenset(
296
+ {
297
+ DatabaseType.postgres,
298
+ DatabaseType.mysql,
299
+ DatabaseType.mariadb,
300
+ DatabaseType.oracle,
301
+ DatabaseType.mssql,
302
+ DatabaseType.db2_luw,
303
+ DatabaseType.redshift,
304
+ }
305
+ )
306
+
307
+
292
308
  class DatabaseConnectionConfig(ConnectionConfig):
293
309
  """
294
310
  Connection configuration for a SQL database.
@@ -309,6 +325,11 @@ class DatabaseConnectionConfig(ConnectionConfig):
309
325
  is_read_only: bool = False
310
326
  s3_bucket_name: Optional[str] = None
311
327
  s3_redshift_iam_role: Optional[str] = None
328
+ # An IAM role for DataMasque to assume when tagging this database's AWS resource after a run.
329
+ # Only the engines in `_AWS_TAGGABLE_DATABASE_TYPES` can be an RDS instance, Aurora cluster or
330
+ # Redshift cluster, so it is pruned for the rest. Distinct from `s3_redshift_iam_role`, which is
331
+ # the role the Redshift cluster itself uses to reach S3.
332
+ iam_role_arn: Optional[str] = None
312
333
 
313
334
  @model_validator(mode="after")
314
335
  def _reject_special_engines(self) -> "DatabaseConnectionConfig":
@@ -348,6 +369,8 @@ class DatabaseConnectionConfig(ConnectionConfig):
348
369
  if db_type is not DatabaseType.redshift:
349
370
  d.pop("s3_bucket_name", None)
350
371
  d.pop("s3_redshift_iam_role", None)
372
+ if db_type not in _AWS_TAGGABLE_DATABASE_TYPES:
373
+ d.pop("iam_role_arn", None)
351
374
  if not d.get("engine_options"):
352
375
  d.pop("engine_options", None)
353
376
  return d
@@ -20,6 +20,7 @@ class ValidationErrorType(enum.Enum):
20
20
  library_missing = "library_missing"
21
21
  library_invalid = "library_invalid"
22
22
  expansion = "expansion" # The ruleset is not valid once its library references are expanded.
23
+ rg_config = "rg_config"
23
24
 
24
25
 
25
26
  class ValidationErrorDetails(BaseModel):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "datamasque-python"
3
- version = "1.2.3"
3
+ version = "1.2.5"
4
4
  description = "Official Python client for the DataMasque data-masking API."
5
5
  authors = [
6
6
  { name = "DataMasque Ltd" },
@@ -1400,3 +1400,86 @@ def test_create_or_update_mongo_connection(client):
1400
1400
  assert sent["db_type"] == "mongodb"
1401
1401
  assert sent["dbpassword"] == "hunter2"
1402
1402
  assert sent["replica_set"] == "rs0"
1403
+
1404
+
1405
+ def _database_connection(database_type: DatabaseType, **extra) -> DatabaseConnectionConfig:
1406
+ return DatabaseConnectionConfig(
1407
+ name="conn",
1408
+ host="mydb.abc123.ap-southeast-2.rds.amazonaws.com",
1409
+ port=5432,
1410
+ database="db",
1411
+ user="user",
1412
+ password="secret",
1413
+ database_type=database_type,
1414
+ **extra,
1415
+ )
1416
+
1417
+
1418
+ @pytest.mark.parametrize(
1419
+ "database_type",
1420
+ [
1421
+ DatabaseType.postgres,
1422
+ DatabaseType.mysql,
1423
+ DatabaseType.mariadb,
1424
+ DatabaseType.oracle,
1425
+ DatabaseType.mssql,
1426
+ DatabaseType.db2_luw,
1427
+ DatabaseType.redshift,
1428
+ ],
1429
+ )
1430
+ def test_database_connection_sends_tagging_iam_role_for_aws_hosted_engines(database_type):
1431
+ """The engines that can sit behind an RDS, Aurora or Redshift endpoint can carry a tagging role."""
1432
+ extra = (
1433
+ {"s3_bucket_name": "bucket", "s3_redshift_iam_role": "arn:aws:iam::123456789012:role/redshift-s3"}
1434
+ if database_type is DatabaseType.redshift
1435
+ else {}
1436
+ )
1437
+ conn = _database_connection(database_type, iam_role_arn="arn:aws:iam::119836602066:role/tagger", **extra)
1438
+
1439
+ api_dict = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1440
+
1441
+ assert api_dict["iam_role_arn"] == "arn:aws:iam::119836602066:role/tagger"
1442
+
1443
+
1444
+ @pytest.mark.parametrize(
1445
+ "database_type",
1446
+ [
1447
+ DatabaseType.db2i,
1448
+ DatabaseType.informix,
1449
+ DatabaseType.saphana,
1450
+ # The two worth documenting rather than merely covering. `mssql_linked` inherits the field
1451
+ # through `MssqlLinkedServerConnectionConfig` and is excluded only by its own enum value;
1452
+ # `databricks_lakebase` is AWS-hosted, so it reads like an omission from the taggable set
1453
+ # until you know it presents no endpoint tagging can act on.
1454
+ DatabaseType.mssql_linked,
1455
+ DatabaseType.databricks_lakebase,
1456
+ ],
1457
+ )
1458
+ def test_database_connection_omits_tagging_iam_role_for_engines_that_cannot_be_aws_resources(database_type):
1459
+ """Mirrors how `s3_redshift_iam_role` is pruned: the server has no such field on these engines."""
1460
+ conn = _database_connection(database_type, iam_role_arn="arn:aws:iam::119836602066:role/tagger")
1461
+
1462
+ api_dict = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1463
+
1464
+ assert "iam_role_arn" not in api_dict
1465
+
1466
+
1467
+ def test_database_connection_omits_tagging_iam_role_when_unset():
1468
+ conn = _database_connection(DatabaseType.postgres)
1469
+
1470
+ assert "iam_role_arn" not in conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1471
+
1472
+
1473
+ def test_redshift_connection_keeps_its_cluster_s3_role_separate_from_its_tagging_role():
1474
+ """Two ARNs with different meanings: the cluster's own S3 access, and the role DataMasque assumes to tag."""
1475
+ conn = _database_connection(
1476
+ DatabaseType.redshift,
1477
+ s3_bucket_name="bucket",
1478
+ s3_redshift_iam_role="arn:aws:iam::123456789012:role/redshift-s3",
1479
+ iam_role_arn="arn:aws:iam::119836602066:role/tagger",
1480
+ )
1481
+
1482
+ api_dict = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1483
+
1484
+ assert api_dict["s3_redshift_iam_role"] == "arn:aws:iam::123456789012:role/redshift-s3"
1485
+ assert api_dict["iam_role_arn"] == "arn:aws:iam::119836602066:role/tagger"
@@ -419,7 +419,7 @@ toml = [
419
419
 
420
420
  [[package]]
421
421
  name = "datamasque-python"
422
- version = "1.2.3"
422
+ version = "1.2.5"
423
423
  source = { editable = "." }
424
424
  dependencies = [
425
425
  { name = "pydantic" },