datamasque-python 1.3.1__py3-none-any.whl → 1.5.0__py3-none-any.whl
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.
- datamasque/client/__init__.py +10 -2
- datamasque/client/models/connection.py +224 -23
- datamasque/client/models/ruleset.py +7 -0
- datamasque/client/models/ruleset_library.py +7 -0
- datamasque/client/ruleset_libraries.py +4 -1
- datamasque/client/rulesets.py +2 -1
- {datamasque_python-1.3.1.dist-info → datamasque_python-1.5.0.dist-info}/METADATA +1 -1
- {datamasque_python-1.3.1.dist-info → datamasque_python-1.5.0.dist-info}/RECORD +10 -10
- {datamasque_python-1.3.1.dist-info → datamasque_python-1.5.0.dist-info}/WHEEL +1 -1
- {datamasque_python-1.3.1.dist-info → datamasque_python-1.5.0.dist-info}/licenses/LICENSE +0 -0
datamasque/client/__init__.py
CHANGED
|
@@ -29,6 +29,7 @@ from datamasque.client.exceptions import (
|
|
|
29
29
|
from datamasque.client.ifm import DataMasqueIfmClient
|
|
30
30
|
from datamasque.client.models.connection import (
|
|
31
31
|
AzureConnectionConfig,
|
|
32
|
+
CassandraConnectionConfig,
|
|
32
33
|
ConnectionConfig,
|
|
33
34
|
ConnectionId,
|
|
34
35
|
CosmosDbConnectionConfig,
|
|
@@ -38,12 +39,15 @@ from datamasque.client.models.connection import (
|
|
|
38
39
|
DocumentDbConnectionConfig,
|
|
39
40
|
DynamoConnectionConfig,
|
|
40
41
|
FileConnectionConfig,
|
|
42
|
+
GcsConnectionConfig,
|
|
43
|
+
LicenseLock,
|
|
41
44
|
MongoConnectionConfig,
|
|
42
45
|
MountedShareConnectionConfig,
|
|
43
46
|
MssqlLinkedServerConnectionConfig,
|
|
44
47
|
S3ConnectionConfig,
|
|
48
|
+
SalesforceConnectionConfig,
|
|
49
|
+
SapAseConnectionConfig,
|
|
45
50
|
SnowflakeConnectionConfig,
|
|
46
|
-
SnowflakeStageLocation,
|
|
47
51
|
SseConfig,
|
|
48
52
|
SseSelection,
|
|
49
53
|
)
|
|
@@ -178,6 +182,7 @@ __all__ = [
|
|
|
178
182
|
"AzureConnectionConfig",
|
|
179
183
|
"BooleanPreview",
|
|
180
184
|
"BooleanStatistics",
|
|
185
|
+
"CassandraConnectionConfig",
|
|
181
186
|
"ColumnKind",
|
|
182
187
|
"ColumnPreview",
|
|
183
188
|
"CommonStatistics",
|
|
@@ -225,6 +230,7 @@ __all__ = [
|
|
|
225
230
|
"FileRulesetGenerationWithRGConfigRequest",
|
|
226
231
|
"FirstCharsStatistics",
|
|
227
232
|
"ForeignKeyRef",
|
|
233
|
+
"GcsConnectionConfig",
|
|
228
234
|
"GitSnapshot",
|
|
229
235
|
"HashColumnsTableConfig",
|
|
230
236
|
"IfmAuthError",
|
|
@@ -243,6 +249,7 @@ __all__ = [
|
|
|
243
249
|
"LengthUnit",
|
|
244
250
|
"LengthsStatistics",
|
|
245
251
|
"LicenseInfo",
|
|
252
|
+
"LicenseLock",
|
|
246
253
|
"Locator",
|
|
247
254
|
"MaskType",
|
|
248
255
|
"MaskedFormEntry",
|
|
@@ -285,6 +292,8 @@ __all__ = [
|
|
|
285
292
|
"S3ConnectionConfig",
|
|
286
293
|
"SafeDataPreview",
|
|
287
294
|
"SafeDataPreviewOptions",
|
|
295
|
+
"SalesforceConnectionConfig",
|
|
296
|
+
"SapAseConnectionConfig",
|
|
288
297
|
"SchemaDiscoveryColumn",
|
|
289
298
|
"SchemaDiscoveryFromConfigRequest",
|
|
290
299
|
"SchemaDiscoveryPage",
|
|
@@ -296,7 +305,6 @@ __all__ = [
|
|
|
296
305
|
"SelectedFileData",
|
|
297
306
|
"SnowflakeConnectionConfig",
|
|
298
307
|
"SnowflakeKeyFile",
|
|
299
|
-
"SnowflakeStageLocation",
|
|
300
308
|
"SseConfig",
|
|
301
309
|
"SseSelection",
|
|
302
310
|
"SslZipFile",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Connection configuration models for the DataMasque API."""
|
|
2
2
|
|
|
3
|
+
from datetime import datetime
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from typing import Any, Callable, Literal, NewType, Optional
|
|
5
6
|
|
|
@@ -50,15 +51,9 @@ class DatabaseType(Enum):
|
|
|
50
51
|
databricks = "databricks"
|
|
51
52
|
informix = "informix"
|
|
52
53
|
saphana = "saphana"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"""Storage backend for a Snowflake connection's external stage."""
|
|
57
|
-
|
|
58
|
-
local = "local" # Not supported for production use
|
|
59
|
-
aws_s3 = "aws_s3"
|
|
60
|
-
azure_blob_storage = "azure_blob_storage"
|
|
61
|
-
spcs = "spcs" # DataMasque running inside Snowflake SPCS; staged on the container's own storage
|
|
54
|
+
cassandra = "cassandra"
|
|
55
|
+
sap_ase = "sap_ase"
|
|
56
|
+
salesforce = "salesforce"
|
|
62
57
|
|
|
63
58
|
|
|
64
59
|
class SseSelection(Enum):
|
|
@@ -99,6 +94,22 @@ class SseConfig(BaseModel):
|
|
|
99
94
|
return self
|
|
100
95
|
|
|
101
96
|
|
|
97
|
+
class LicenseLock(BaseModel):
|
|
98
|
+
"""
|
|
99
|
+
Read-only license-lock metadata for a connection.
|
|
100
|
+
|
|
101
|
+
The server reports this only on instances whose license has a finite connection cap
|
|
102
|
+
and counts this connection's type against that cap,
|
|
103
|
+
once the connection's first run has finished successfully;
|
|
104
|
+
otherwise it is `null`.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
model_config = ConfigDict(extra="allow")
|
|
108
|
+
|
|
109
|
+
locked_at: datetime
|
|
110
|
+
editable_from: datetime
|
|
111
|
+
|
|
112
|
+
|
|
102
113
|
class ConnectionConfig(BaseModel):
|
|
103
114
|
"""
|
|
104
115
|
Base class for all connection configurations.
|
|
@@ -111,6 +122,16 @@ class ConnectionConfig(BaseModel):
|
|
|
111
122
|
|
|
112
123
|
name: str
|
|
113
124
|
id: Optional[ConnectionId] = None
|
|
125
|
+
# Server-populated and read-only, so it is excluded when serializing a config back to the API.
|
|
126
|
+
license_lock: Optional[LicenseLock] = Field(default=None, exclude=True)
|
|
127
|
+
# Whether the connection's protected fields are currently locked under the license edit lock.
|
|
128
|
+
target_frozen: bool = Field(default=False, exclude=True)
|
|
129
|
+
# The protected fields currently locked, as server config keys (e.g. `schema`, not `db_schema`);
|
|
130
|
+
# empty when `target_frozen` is False.
|
|
131
|
+
frozen_target_fields: list[str] = Field(default_factory=list, exclude=True)
|
|
132
|
+
# Whether deleting the connection is currently blocked. Not always equal to `target_frozen`:
|
|
133
|
+
# deletion stays allowed while over the connection cap, so a downgrade can be recovered from.
|
|
134
|
+
deletion_frozen: bool = Field(default=False, exclude=True)
|
|
114
135
|
|
|
115
136
|
|
|
116
137
|
class DynamoConnectionConfig(ConnectionConfig):
|
|
@@ -258,6 +279,19 @@ class CosmosDbConnectionConfig(MongoConnectionConfig):
|
|
|
258
279
|
return DatabaseType.cosmosdb
|
|
259
280
|
|
|
260
281
|
|
|
282
|
+
# Servers before 3.26.18 still return these on Snowflake connections. With `extra="allow"`
|
|
283
|
+
# they would be sent back on create/update unless dropped here.
|
|
284
|
+
_SNOWFLAKE_EXTERNAL_STAGE_KEYS = (
|
|
285
|
+
"s3_bucket_name",
|
|
286
|
+
"iam_role_arn",
|
|
287
|
+
"snowflake_azure_container_name",
|
|
288
|
+
"snowflake_azure_connection_string",
|
|
289
|
+
"snowflake_azure_connection_string_encrypted",
|
|
290
|
+
"snowflake_storage_integration_name",
|
|
291
|
+
"snowflake_stage_location",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
|
|
261
295
|
class SnowflakeConnectionConfig(ConnectionConfig):
|
|
262
296
|
"""
|
|
263
297
|
Connection configuration for a Snowflake database.
|
|
@@ -267,14 +301,14 @@ class SnowflakeConnectionConfig(ConnectionConfig):
|
|
|
267
301
|
"""
|
|
268
302
|
|
|
269
303
|
database: str
|
|
270
|
-
# Optional because
|
|
271
|
-
#
|
|
272
|
-
#
|
|
273
|
-
#
|
|
304
|
+
# Optional because connections leave these unset when DataMasque runs inside Snowflake SPCS:
|
|
305
|
+
# the server detects SPCS from its environment and the agent uses the container's OAuth token,
|
|
306
|
+
# the SNOWFLAKE_HOST/SNOWFLAKE_ACCOUNT env and the app-owned QUERY_WAREHOUSE, so user/account/
|
|
307
|
+
# warehouse are None. Mirrors the app's canonical model
|
|
308
|
+
# (agent .../schemas/connection/connection.py), which types these `| None = None`.
|
|
274
309
|
user: Optional[str] = None
|
|
275
310
|
snowflake_account_id: Optional[str] = None
|
|
276
311
|
snowflake_warehouse: Optional[str] = None
|
|
277
|
-
snowflake_storage_integration_name: Optional[str] = None
|
|
278
312
|
host: str = ""
|
|
279
313
|
port: Optional[int] = None
|
|
280
314
|
db_schema: Optional[str] = Field(default=None, alias="schema")
|
|
@@ -283,12 +317,6 @@ class SnowflakeConnectionConfig(ConnectionConfig):
|
|
|
283
317
|
password: Optional[str] = None
|
|
284
318
|
snowflake_private_key: Optional[FileId] = None
|
|
285
319
|
snowflake_private_key_passphrase: Optional[str] = None
|
|
286
|
-
snowflake_stage_location: Optional[SnowflakeStageLocation] = None
|
|
287
|
-
s3_bucket_name: Optional[str] = None
|
|
288
|
-
iam_role_arn: Optional[str] = None
|
|
289
|
-
snowflake_azure_container_name: Optional[str] = None
|
|
290
|
-
snowflake_azure_connection_string: Optional[str] = None
|
|
291
|
-
snowflake_azure_connection_string_encrypted: Optional[str] = None
|
|
292
320
|
|
|
293
321
|
mask_type: Literal["database"] = "database"
|
|
294
322
|
db_type: Literal["snowflake"] = "snowflake"
|
|
@@ -311,9 +339,9 @@ class SnowflakeConnectionConfig(ConnectionConfig):
|
|
|
311
339
|
|
|
312
340
|
@model_validator(mode="before")
|
|
313
341
|
@classmethod
|
|
314
|
-
def
|
|
342
|
+
def _strip_server_only_fields(cls, data: dict) -> dict:
|
|
315
343
|
if isinstance(data, dict):
|
|
316
|
-
for key in ("password_encrypted", "dbpassword"):
|
|
344
|
+
for key in ("password_encrypted", "dbpassword", *_SNOWFLAKE_EXTERNAL_STAGE_KEYS):
|
|
317
345
|
data.pop(key, None)
|
|
318
346
|
return data
|
|
319
347
|
|
|
@@ -339,7 +367,8 @@ class DatabaseConnectionConfig(ConnectionConfig):
|
|
|
339
367
|
Connection configuration for a SQL database.
|
|
340
368
|
|
|
341
369
|
Use `DynamoConnectionConfig` for DynamoDB, `SnowflakeConnectionConfig` for Snowflake,
|
|
342
|
-
|
|
370
|
+
`MongoConnectionConfig` for MongoDB, `CassandraConnectionConfig` for Apache Cassandra,
|
|
371
|
+
`SapAseConnectionConfig` for SAP ASE (Sybase) and `SalesforceConnectionConfig` for Salesforce.
|
|
343
372
|
"""
|
|
344
373
|
|
|
345
374
|
host: str
|
|
@@ -374,6 +403,12 @@ class DatabaseConnectionConfig(ConnectionConfig):
|
|
|
374
403
|
raise ValueError("For Azure Cosmos DB, use the CosmosDbConnectionConfig class instead")
|
|
375
404
|
if self.database_type is DatabaseType.databricks:
|
|
376
405
|
raise ValueError("For Databricks SQL Warehouse, use the DatabricksConnectionConfig class instead")
|
|
406
|
+
if self.database_type is DatabaseType.cassandra:
|
|
407
|
+
raise ValueError("For Apache Cassandra, use the CassandraConnectionConfig class instead")
|
|
408
|
+
if self.database_type is DatabaseType.sap_ase:
|
|
409
|
+
raise ValueError("For SAP ASE (Sybase), use the SapAseConnectionConfig class instead")
|
|
410
|
+
if self.database_type is DatabaseType.salesforce:
|
|
411
|
+
raise ValueError("For Salesforce, use the SalesforceConnectionConfig class instead")
|
|
377
412
|
return self
|
|
378
413
|
|
|
379
414
|
mask_type: Literal["database"] = "database"
|
|
@@ -481,6 +516,29 @@ class AzureConnectionConfig(FileConnectionConfig):
|
|
|
481
516
|
return data
|
|
482
517
|
|
|
483
518
|
|
|
519
|
+
class GcsConnectionConfig(FileConnectionConfig):
|
|
520
|
+
"""
|
|
521
|
+
Connection configuration for a Google Cloud Storage bucket.
|
|
522
|
+
|
|
523
|
+
`service_account_key` holds the contents of a service account's JSON key file,
|
|
524
|
+
or the ARN of an AWS Secrets Manager secret that holds it.
|
|
525
|
+
|
|
526
|
+
Requires server version 3.26.19.
|
|
527
|
+
"""
|
|
528
|
+
|
|
529
|
+
type: Literal["gcs_connection"] = "gcs_connection"
|
|
530
|
+
bucket: str = ""
|
|
531
|
+
service_account_key: Optional[str] = None
|
|
532
|
+
|
|
533
|
+
@model_validator(mode="before")
|
|
534
|
+
@classmethod
|
|
535
|
+
def _strip_encrypted_service_account_key(cls, data: dict) -> dict:
|
|
536
|
+
if isinstance(data, dict):
|
|
537
|
+
# The API returns the encrypted form; drop it so `service_account_key` stays None.
|
|
538
|
+
data.pop("service_account_key_encrypted", None)
|
|
539
|
+
return data
|
|
540
|
+
|
|
541
|
+
|
|
484
542
|
class MountedShareConnectionConfig(FileConnectionConfig):
|
|
485
543
|
"""Connection configuration for a mounted file share."""
|
|
486
544
|
|
|
@@ -513,9 +571,149 @@ class DatabricksConnectionConfig(ConnectionConfig):
|
|
|
513
571
|
return data
|
|
514
572
|
|
|
515
573
|
|
|
574
|
+
class CassandraConnectionConfig(ConnectionConfig):
|
|
575
|
+
"""
|
|
576
|
+
Connection configuration for an Apache Cassandra keyspace.
|
|
577
|
+
|
|
578
|
+
`database` is the keyspace.
|
|
579
|
+
`user` and `password` are optional, but a username needs a password.
|
|
580
|
+
Set `direct_connection` when the node addresses the cluster advertises are unreachable,
|
|
581
|
+
for example behind NAT or in containers.
|
|
582
|
+
|
|
583
|
+
Requires server version 3.26.19.
|
|
584
|
+
"""
|
|
585
|
+
|
|
586
|
+
host: str
|
|
587
|
+
port: int = 9042
|
|
588
|
+
database: str
|
|
589
|
+
user: Optional[str] = None
|
|
590
|
+
password: Optional[str] = None
|
|
591
|
+
local_datacenter: Optional[str] = None
|
|
592
|
+
tls: bool = False
|
|
593
|
+
direct_connection: bool = False
|
|
594
|
+
is_read_only: bool = False
|
|
595
|
+
|
|
596
|
+
mask_type: Literal["database"] = "database"
|
|
597
|
+
db_type: Literal["cassandra"] = "cassandra"
|
|
598
|
+
|
|
599
|
+
@property
|
|
600
|
+
def database_type(self) -> DatabaseType:
|
|
601
|
+
return DatabaseType.cassandra
|
|
602
|
+
|
|
603
|
+
@model_serializer(mode="wrap")
|
|
604
|
+
def _serialize(self, handler: Callable) -> dict:
|
|
605
|
+
d = handler(self)
|
|
606
|
+
# The server expects the password under the `dbpassword` key.
|
|
607
|
+
password = d.pop("password", None)
|
|
608
|
+
if password is not None:
|
|
609
|
+
d["dbpassword"] = password
|
|
610
|
+
return d
|
|
611
|
+
|
|
612
|
+
@model_validator(mode="before")
|
|
613
|
+
@classmethod
|
|
614
|
+
def _strip_encrypted_password(cls, data: dict) -> dict:
|
|
615
|
+
if isinstance(data, dict):
|
|
616
|
+
for key in ("password_encrypted", "dbpassword"):
|
|
617
|
+
data.pop(key, None)
|
|
618
|
+
return data
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
class SapAseConnectionConfig(ConnectionConfig):
|
|
622
|
+
"""
|
|
623
|
+
Connection configuration for an SAP ASE (Sybase) database.
|
|
624
|
+
|
|
625
|
+
ASE has no schema setting: the schema is the table owner,
|
|
626
|
+
and an unqualified name resolves to the connecting user's table first, then to `dbo`'s.
|
|
627
|
+
With `tls` on, the server certificate is always verified;
|
|
628
|
+
`tls_server_name` only changes the name it is verified against.
|
|
629
|
+
|
|
630
|
+
Requires server version 3.26.19.
|
|
631
|
+
"""
|
|
632
|
+
|
|
633
|
+
host: str
|
|
634
|
+
port: int = 5000
|
|
635
|
+
database: str
|
|
636
|
+
user: str
|
|
637
|
+
password: Optional[str] = None
|
|
638
|
+
tls: bool = False
|
|
639
|
+
tls_server_name: Optional[str] = None
|
|
640
|
+
connect_timeout: Optional[int] = None
|
|
641
|
+
is_read_only: bool = False
|
|
642
|
+
|
|
643
|
+
mask_type: Literal["database"] = "database"
|
|
644
|
+
db_type: Literal["sap_ase"] = "sap_ase"
|
|
645
|
+
|
|
646
|
+
@property
|
|
647
|
+
def database_type(self) -> DatabaseType:
|
|
648
|
+
return DatabaseType.sap_ase
|
|
649
|
+
|
|
650
|
+
@model_serializer(mode="wrap")
|
|
651
|
+
def _serialize(self, handler: Callable) -> dict:
|
|
652
|
+
d = handler(self)
|
|
653
|
+
# The server expects the password under the `dbpassword` key.
|
|
654
|
+
password = d.pop("password", None)
|
|
655
|
+
if password is not None:
|
|
656
|
+
d["dbpassword"] = password
|
|
657
|
+
return d
|
|
658
|
+
|
|
659
|
+
@model_validator(mode="before")
|
|
660
|
+
@classmethod
|
|
661
|
+
def _strip_encrypted_password(cls, data: dict) -> dict:
|
|
662
|
+
if isinstance(data, dict):
|
|
663
|
+
for key in ("password_encrypted", "dbpassword"):
|
|
664
|
+
data.pop(key, None)
|
|
665
|
+
return data
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
class SalesforceConnectionConfig(ConnectionConfig):
|
|
669
|
+
"""
|
|
670
|
+
Connection configuration for a Salesforce org.
|
|
671
|
+
|
|
672
|
+
Salesforce is reached over HTTPS with an OAuth JWT bearer assertion,
|
|
673
|
+
so it carries no host, port, database or password.
|
|
674
|
+
`login_url` is the org's My Domain URL and is sent verbatim as the JWT audience,
|
|
675
|
+
which Salesforce compares exactly.
|
|
676
|
+
`salesforce_private_key_path` is relative to the DataMasque files sandbox,
|
|
677
|
+
or to the connection fileset when one is attached.
|
|
678
|
+
`salesforce_private_key_passphrase` is only needed for an encrypted key.
|
|
679
|
+
`api_version` is the server's default unless set.
|
|
680
|
+
|
|
681
|
+
Requires server version 3.26.19.
|
|
682
|
+
Salesforce is a preview connection type there:
|
|
683
|
+
the server refuses to create one until an administrator enables preview features
|
|
684
|
+
under Settings, Preview Features.
|
|
685
|
+
"""
|
|
686
|
+
|
|
687
|
+
instance_url: str
|
|
688
|
+
login_url: str
|
|
689
|
+
client_id: str
|
|
690
|
+
user: str
|
|
691
|
+
salesforce_private_key_path: str
|
|
692
|
+
salesforce_private_key_passphrase: Optional[str] = None
|
|
693
|
+
# Left unset so the server applies its own default, which it stores on the connection.
|
|
694
|
+
# A default here would keep pinning new connections to it after the server moves on.
|
|
695
|
+
api_version: Optional[str] = None
|
|
696
|
+
is_read_only: bool = False
|
|
697
|
+
|
|
698
|
+
mask_type: Literal["database"] = "database"
|
|
699
|
+
db_type: Literal["salesforce"] = "salesforce"
|
|
700
|
+
|
|
701
|
+
@property
|
|
702
|
+
def database_type(self) -> DatabaseType:
|
|
703
|
+
return DatabaseType.salesforce
|
|
704
|
+
|
|
705
|
+
@model_validator(mode="before")
|
|
706
|
+
@classmethod
|
|
707
|
+
def _strip_encrypted_passphrase(cls, data: dict) -> dict:
|
|
708
|
+
if isinstance(data, dict):
|
|
709
|
+
data.pop("salesforce_private_key_passphrase_encrypted", None)
|
|
710
|
+
return data
|
|
711
|
+
|
|
712
|
+
|
|
516
713
|
FILE_TYPE_MAP: dict[str, type[FileConnectionConfig]] = {
|
|
517
714
|
"s3_connection": S3ConnectionConfig,
|
|
518
715
|
"azure_blob_connection": AzureConnectionConfig,
|
|
716
|
+
"gcs_connection": GcsConnectionConfig,
|
|
519
717
|
"mounted_share_connection": MountedShareConnectionConfig,
|
|
520
718
|
}
|
|
521
719
|
|
|
@@ -527,6 +725,9 @@ DB_TYPE_MAP: dict[str, type[ConnectionConfig]] = {
|
|
|
527
725
|
DatabaseType.snowflake.value: SnowflakeConnectionConfig,
|
|
528
726
|
DatabaseType.mssql_linked.value: MssqlLinkedServerConnectionConfig,
|
|
529
727
|
DatabaseType.databricks.value: DatabricksConnectionConfig,
|
|
728
|
+
DatabaseType.cassandra.value: CassandraConnectionConfig,
|
|
729
|
+
DatabaseType.sap_ase.value: SapAseConnectionConfig,
|
|
730
|
+
DatabaseType.salesforce.value: SalesforceConnectionConfig,
|
|
530
731
|
# others use the default `DatabaseConnectionConfig`
|
|
531
732
|
}
|
|
532
733
|
|
|
@@ -46,3 +46,10 @@ class Ruleset(GitTrackedEntity):
|
|
|
46
46
|
is_valid: Optional[ValidationStatus] = Field(default=None, exclude=True)
|
|
47
47
|
validation_errors: list[ValidationErrorDetails] = Field(default_factory=list, exclude=True)
|
|
48
48
|
"""Validation errors surfaced by the server; empty when valid."""
|
|
49
|
+
unlicensed_feature_warnings: Optional[list[str]] = Field(default=None, exclude=True)
|
|
50
|
+
"""
|
|
51
|
+
At most one sentence, naming every feature the ruleset uses that the server's license does not allow.
|
|
52
|
+
Empty when the ruleset needs nothing its license withholds,
|
|
53
|
+
and `None` when the server does not know which features the ruleset uses, for example before it has passed
|
|
54
|
+
validation. `None` is not the same as having no warnings.
|
|
55
|
+
"""
|
|
@@ -21,5 +21,12 @@ class RulesetLibrary(GitTrackedEntity):
|
|
|
21
21
|
is_valid: Optional[ValidationStatus] = Field(default=None, exclude=True)
|
|
22
22
|
validation_errors: list[ValidationErrorDetails] = Field(default_factory=list, exclude=True)
|
|
23
23
|
"""Validation errors surfaced by the server; empty when valid."""
|
|
24
|
+
unlicensed_feature_warnings: Optional[list[str]] = Field(default=None, exclude=True)
|
|
25
|
+
"""
|
|
26
|
+
At most one sentence, naming every feature the library uses that the server's license does not allow.
|
|
27
|
+
Empty when the license allows every feature,
|
|
28
|
+
and `None` when the server does not know which features the library uses, for example before it has passed
|
|
29
|
+
validation.
|
|
30
|
+
"""
|
|
24
31
|
created: Optional[datetime] = Field(default=None, exclude=True)
|
|
25
32
|
modified: Optional[datetime] = Field(default=None, exclude=True)
|
|
@@ -64,7 +64,8 @@ class RulesetLibraryClient(BaseClient):
|
|
|
64
64
|
Creates a new ruleset library on the server.
|
|
65
65
|
|
|
66
66
|
Sets the library's server-assigned fields
|
|
67
|
-
(`id`, `is_valid`, `validation_errors`, `git`, `created`, `modified`)
|
|
67
|
+
(`id`, `is_valid`, `validation_errors`, `unlicensed_feature_warnings`, `git`, `created`, `modified`)
|
|
68
|
+
and returns the library.
|
|
68
69
|
"""
|
|
69
70
|
|
|
70
71
|
data = library.model_dump(exclude_none=True, by_alias=True, mode="json")
|
|
@@ -73,6 +74,7 @@ class RulesetLibraryClient(BaseClient):
|
|
|
73
74
|
library.id = created_library.id
|
|
74
75
|
library.is_valid = created_library.is_valid
|
|
75
76
|
library.validation_errors = created_library.validation_errors
|
|
77
|
+
library.unlicensed_feature_warnings = created_library.unlicensed_feature_warnings
|
|
76
78
|
library.git = created_library.git
|
|
77
79
|
library.created = created_library.created
|
|
78
80
|
library.modified = created_library.modified
|
|
@@ -94,6 +96,7 @@ class RulesetLibraryClient(BaseClient):
|
|
|
94
96
|
updated_library = RulesetLibrary.model_validate(response.json())
|
|
95
97
|
library.is_valid = updated_library.is_valid
|
|
96
98
|
library.validation_errors = updated_library.validation_errors
|
|
99
|
+
library.unlicensed_feature_warnings = updated_library.unlicensed_feature_warnings
|
|
97
100
|
library.git = updated_library.git
|
|
98
101
|
library.modified = updated_library.modified
|
|
99
102
|
logger.debug('Update of ruleset library "%s" successful', library.name)
|
datamasque/client/rulesets.py
CHANGED
|
@@ -20,7 +20,7 @@ class RulesetClient(BaseClient):
|
|
|
20
20
|
"""
|
|
21
21
|
Creates or updates a ruleset.
|
|
22
22
|
|
|
23
|
-
Populates the given ruleset's `id`, `is_valid`, `validation_errors`,
|
|
23
|
+
Populates the given ruleset's `id`, `is_valid`, `validation_errors`, `unlicensed_feature_warnings`,
|
|
24
24
|
and `git` fields from the server response, and returns the same ruleset instance for convenience.
|
|
25
25
|
"""
|
|
26
26
|
|
|
@@ -30,6 +30,7 @@ class RulesetClient(BaseClient):
|
|
|
30
30
|
ruleset.id = created.id
|
|
31
31
|
ruleset.is_valid = created.is_valid
|
|
32
32
|
ruleset.validation_errors = created.validation_errors
|
|
33
|
+
ruleset.unlicensed_feature_warnings = created.unlicensed_feature_warnings
|
|
33
34
|
ruleset.git = created.git
|
|
34
35
|
|
|
35
36
|
if response.status_code == 201:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: datamasque-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
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/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
datamasque/client/__init__.py,sha256=
|
|
1
|
+
datamasque/client/__init__.py,sha256=E763HBSVk3NOMI-sAchHwwAB1eG40A_6FN6vixNVJ4s,9021
|
|
2
2
|
datamasque/client/base.py,sha256=cXU4dluL9e1N1F2pV48iIvebv6OHt7Kh4Ka2y9vkOPo,14296
|
|
3
3
|
datamasque/client/connections.py,sha256=EFinx8fJRme0mTxuWY3d29UnmUFbsQhMaUQT0Ma2PK4,2885
|
|
4
4
|
datamasque/client/discovery.py,sha256=xidiAj5LdVSGQy6pjta_2Z_aJmuPPohblyNDfua_Mxk,28859
|
|
@@ -11,15 +11,15 @@ datamasque/client/ifm.py,sha256=uIMxpLIPvDiDO1m4bxezixNIUFIFY0MXWRMQNvTbpTA,1185
|
|
|
11
11
|
datamasque/client/license.py,sha256=pluYaSU168OC6_laB9bM9H3Vuuxs8wa9gujCJvtoJCk,1392
|
|
12
12
|
datamasque/client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
datamasque/client/rg_configs.py,sha256=jcrbw-oMhj6o3Wsf8xy3peVo7DzeQ8EhhAsfcEwC3lc,5816
|
|
14
|
-
datamasque/client/ruleset_libraries.py,sha256=
|
|
15
|
-
datamasque/client/rulesets.py,sha256=
|
|
14
|
+
datamasque/client/ruleset_libraries.py,sha256=1eVLFn1uQruhP81X2m7kKxtmcA-HG4lNMLr8jSuX0DU,7494
|
|
15
|
+
datamasque/client/rulesets.py,sha256=G8oFz-Y7b6mGjWQYANzihXxqlCMWRXu38tNlerXhIE8,2676
|
|
16
16
|
datamasque/client/runs.py,sha256=l_JpYgelqsDKW_O6LtsHC60IMXHG9ak_RwVnuvJKE1I,7703
|
|
17
17
|
datamasque/client/settings.py,sha256=Ui8AyR2XdoW8MZ9FIrGn2jm8DLzUGWIL8i2DOTvu7hc,2898
|
|
18
18
|
datamasque/client/spcs.py,sha256=geHrBQ6WLWsMGpSMV8hmK5SFAwftrOU0DXkrR2orOmo,7532
|
|
19
19
|
datamasque/client/table_references.py,sha256=dPyB59Sz4iLuF1lc7xffgf9qeNTFA5srT55E8TnFLvk,6092
|
|
20
20
|
datamasque/client/users.py,sha256=VCUo2CJyOw4-aO_3mp_w_0BcSoa6-h1HcReMcAMyumw,3701
|
|
21
21
|
datamasque/client/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
datamasque/client/models/connection.py,sha256=
|
|
22
|
+
datamasque/client/models/connection.py,sha256=TMouaCcxT_Vwl2lBfPK-PbIhTdKxRqR5NNcRY7lwX38,27572
|
|
23
23
|
datamasque/client/models/data_selection.py,sha256=9hRpkQQIQlKGFYDYQCrreggsv96dh6DelppCpCE4S2U,2725
|
|
24
24
|
datamasque/client/models/discovery.py,sha256=BvAK9zj0jwUc1O4DSluMcjeoYhF4HKOkJmO4uAhzet4,18222
|
|
25
25
|
datamasque/client/models/discovery_config.py,sha256=8sqs9x_X0H_hR1fJDEFmOdJyGRDwgbdb3eddEAe98WE,2420
|
|
@@ -31,14 +31,14 @@ datamasque/client/models/ifm.py,sha256=j0Ef2BZYTk6MNZO6HS6mW0qWs1_wWD9PlUP_Y6WyB
|
|
|
31
31
|
datamasque/client/models/license.py,sha256=OqIn4Sx3ATBStgt5KNiCOBChTTFYLBsyGj7inAl8oB4,2113
|
|
32
32
|
datamasque/client/models/pagination.py,sha256=egg9aO2cf6KUDwDANPu5RxpJbdRKdwUdCQAtusnuf1c,651
|
|
33
33
|
datamasque/client/models/rg_config.py,sha256=g6g0qMTeR6OcM4Ji8fHrDOnOM5fsz1UYxntn_mv_k88,1792
|
|
34
|
-
datamasque/client/models/ruleset.py,sha256=
|
|
35
|
-
datamasque/client/models/ruleset_library.py,sha256=
|
|
34
|
+
datamasque/client/models/ruleset.py,sha256=q8p24uVZQtlSOdmyyF1g_xU4zp7JYhfGOExs13TzkKg,1997
|
|
35
|
+
datamasque/client/models/ruleset_library.py,sha256=VzJDCH-TGTLs1CcQ6Jv4fNW01nksBDQLHuLy-b3hOA0,1390
|
|
36
36
|
datamasque/client/models/runs.py,sha256=UtPMGCJFLFP1f2nyVGAbl3A5_wAONrRNJ63y43Hbpi0,6213
|
|
37
37
|
datamasque/client/models/safe_data_preview.py,sha256=BiI9d13KdQrTin2JfbjiRiODjns_FipWmfcEyfQzN1E,6778
|
|
38
38
|
datamasque/client/models/status.py,sha256=DXcucL_jRsOQ0vaV0t8CJt6crvCIOLBn07KuwpwW-4A,3247
|
|
39
39
|
datamasque/client/models/table_reference.py,sha256=55fKdHjC2TQnUmbp0XiWqfeFGXqcq4wXjbWgMaN3p3c,3835
|
|
40
40
|
datamasque/client/models/user.py,sha256=UGAUzgJkf78m24_zFXXoA99zdut48BXkX_ivV8yq1Vc,2043
|
|
41
|
-
datamasque_python-1.
|
|
42
|
-
datamasque_python-1.
|
|
43
|
-
datamasque_python-1.
|
|
44
|
-
datamasque_python-1.
|
|
41
|
+
datamasque_python-1.5.0.dist-info/METADATA,sha256=8PhvPpCLdPzElNVWl_4CBcBFlTDsPiwly09VSmvoH6s,4497
|
|
42
|
+
datamasque_python-1.5.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
43
|
+
datamasque_python-1.5.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
44
|
+
datamasque_python-1.5.0.dist-info/RECORD,,
|
|
File without changes
|