datamasque-python 1.2.2__py3-none-any.whl → 1.2.4__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.
@@ -81,6 +81,7 @@ from datamasque.client.models.discovery import (
81
81
  SchemaDiscoveryRequest,
82
82
  SchemaDiscoveryResult,
83
83
  TableConstraints,
84
+ ValueCountStatus,
84
85
  )
85
86
  from datamasque.client.models.discovery_config import DiscoveryConfig, DiscoveryConfigId, DiscoveryConfigType
86
87
  from datamasque.client.models.discovery_config_library import DiscoveryConfigLibrary, DiscoveryConfigLibraryId
@@ -319,4 +320,5 @@ __all__ = [
319
320
  "ValidationErrorDetails",
320
321
  "ValidationErrorType",
321
322
  "ValidationStatus",
323
+ "ValueCountStatus",
322
324
  ]
@@ -1,5 +1,6 @@
1
1
  """Models related to data selection in endpoints such as /api/async-generate-ruleset."""
2
2
 
3
+ import json
3
4
  from typing import Optional, Union
4
5
 
5
6
  from pydantic import BaseModel, ConfigDict
@@ -19,6 +20,33 @@ A locator identifying a masked value within a file.
19
20
  """
20
21
 
21
22
 
23
+ def serialize_locator(locator: Locator) -> str:
24
+ """
25
+ Returns the string form of `locator` that the API uses as a key, such as in `FileDiscoveryFile.value_counts`.
26
+
27
+ A string locator is its own key.
28
+ A :data:`JsonPath` becomes compact JSON, e.g. `'["employees","*","email"]'`.
29
+ """
30
+
31
+ if isinstance(locator, str):
32
+ return locator
33
+ return json.dumps(locator, separators=(",", ":"), ensure_ascii=False)
34
+
35
+
36
+ def deserialize_locator(key: str) -> Locator:
37
+ """
38
+ Returns the `Locator` that `key`, a serialized locator from the API, identifies.
39
+
40
+ A key that holds no JSON array names a column, and comes back as a string.
41
+ """
42
+
43
+ try:
44
+ parsed = json.loads(key)
45
+ except json.JSONDecodeError:
46
+ return key
47
+ return parsed if isinstance(parsed, list) else key
48
+
49
+
22
50
  class UserSelection(BaseModel):
23
51
  """Information about selected files and locators for file masking ruleset generation."""
24
52
 
@@ -6,7 +6,13 @@ from typing import Any, Optional, Union
6
6
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
7
7
 
8
8
  from datamasque.client.models.connection import ConnectionConfig, ConnectionId, unwrap_connection_id
9
- from datamasque.client.models.data_selection import HashColumnsTableConfig, Locator, UserSelection
9
+ from datamasque.client.models.data_selection import (
10
+ HashColumnsTableConfig,
11
+ Locator,
12
+ UserSelection,
13
+ deserialize_locator,
14
+ serialize_locator,
15
+ )
10
16
  from datamasque.client.models.discovery_config import DiscoveryConfig, DiscoveryConfigId, unwrap_discovery_config_id
11
17
  from datamasque.client.models.pagination import Page
12
18
  from datamasque.client.models.rg_config import RGConfig, RGConfigId, unwrap_rg_config_id
@@ -434,6 +440,14 @@ class FileDiscoveryMatch(BaseModel):
434
440
  hit_ratio: Optional[int] = None # None for metadata matches, percentage 0-100 for IDD matches.
435
441
 
436
442
 
443
+ class ValueCountStatus(Enum):
444
+ """Whether a file's values were counted, and when they were not, why."""
445
+
446
+ counted = "counted"
447
+ in_data_discovery_disabled = "in_data_discovery_disabled"
448
+ file_type_has_no_values = "file_type_has_no_values"
449
+
450
+
437
451
  class FileDiscoveryLocatorResult(BaseModel):
438
452
  """A locator (column/path) within a discovered file."""
439
453
 
@@ -443,6 +457,7 @@ class FileDiscoveryLocatorResult(BaseModel):
443
457
  matches: list[FileDiscoveryMatch]
444
458
  data_types: list[str]
445
459
  safe_data_preview: Optional[SafeDataPreview] = None
460
+ value_count: Optional[int] = None
446
461
 
447
462
 
448
463
  class FileDiscoveryFile(BaseModel):
@@ -454,6 +469,23 @@ class FileDiscoveryFile(BaseModel):
454
469
  file_type: str
455
470
  delimiter: Optional[str] = None
456
471
  encoding: Optional[str] = None
472
+ value_counts: dict[str, int] = Field(default_factory=dict)
473
+ value_count_status: Optional[ValueCountStatus] = None
474
+
475
+ @field_validator("value_count_status", mode="before")
476
+ @classmethod
477
+ def _blank_status_is_none(cls, value: Any) -> Any:
478
+ return value or None
479
+
480
+ def get_value_count_of_locator(self, locator: Locator) -> Optional[int]:
481
+ """Returns how many values this file holds at `locator`, or `None` if this file holds no count for it."""
482
+
483
+ return self.value_counts.get(serialize_locator(locator))
484
+
485
+ def parse_value_counts(self) -> list[tuple[Locator, int]]:
486
+ """Returns this file's value counts, with each locator in the form that the discovery results use."""
487
+
488
+ return [(deserialize_locator(key), count) for key, count in self.value_counts.items()]
457
489
 
458
490
 
459
491
  class FileDiscoveryResult(BaseModel):
@@ -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
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: datamasque-python
3
- Version: 1.2.2
3
+ Version: 1.2.4
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=2PVF5FrXkPAv51EMxSvfpYelJpbOg_Tlx-Wo7p2-0jo,8661
1
+ datamasque/client/__init__.py,sha256=bw_5NEF3vLuOLKrT-z7UCkWaR_nFVkhE_RmY3Q9Y7sw,8707
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
@@ -20,8 +20,8 @@ datamasque/client/table_references.py,sha256=dPyB59Sz4iLuF1lc7xffgf9qeNTFA5srT55
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
22
  datamasque/client/models/connection.py,sha256=loLy4RCiIfY9kvBFspSqJSRhHqhcJxm_mQzXwMRS4VU,17529
23
- datamasque/client/models/data_selection.py,sha256=406yyUZ5NmLBSql2lYM1gsTWY5GWmnutmF-DjznAoLc,1904
24
- datamasque/client/models/discovery.py,sha256=Ejtrmja_wjHRxCWZel5Q5nZz4M20F2zdtBsdhWI1BnA,16791
23
+ datamasque/client/models/data_selection.py,sha256=9hRpkQQIQlKGFYDYQCrreggsv96dh6DelppCpCE4S2U,2725
24
+ datamasque/client/models/discovery.py,sha256=J_cAXuIpoQTzHh_-1zvBwXsFnbKI2hRywALb5Yfc5vI,17955
25
25
  datamasque/client/models/discovery_config.py,sha256=8sqs9x_X0H_hR1fJDEFmOdJyGRDwgbdb3eddEAe98WE,2420
26
26
  datamasque/client/models/discovery_config_library.py,sha256=m0wI51Q4aHysLNHyNTWH3KrDLV_rxtoLNeKQsF9RYFk,1436
27
27
  datamasque/client/models/dm_instance.py,sha256=6h0WNlI1qt6jkrYFapIvuSJFkhRCcwbpx0PLG5NsrGw,2219
@@ -35,10 +35,10 @@ datamasque/client/models/ruleset.py,sha256=FDnvewJQvbeH73LpZiwYg3BG9Ya4yhmKKGmO1
35
35
  datamasque/client/models/ruleset_library.py,sha256=Pw6Udr7pMgPt1AcG2ZhUXOPBS7tTvpw13UZNLILhZbQ,1003
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
- datamasque/client/models/status.py,sha256=WiSMEy_YxdcIA46ioYpAEu8OK8UNDoXpV1W7IUhhyVY,3219
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.2.2.dist-info/METADATA,sha256=ir-yTNm-rFL887aT4tQN1iTe6Ll10VNBUvy2n7JTF3k,4497
42
- datamasque_python-1.2.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
43
- datamasque_python-1.2.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
44
- datamasque_python-1.2.2.dist-info/RECORD,,
41
+ datamasque_python-1.2.4.dist-info/METADATA,sha256=JfLuGmshJx1zHMoPocIbxfuO3H3jMKAJEa5hPTnKPNM,4497
42
+ datamasque_python-1.2.4.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
43
+ datamasque_python-1.2.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
44
+ datamasque_python-1.2.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.31.0
2
+ Generator: hatchling 1.32.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any