datamasque-python 1.2.2__tar.gz → 1.2.4__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.
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/HISTORY.rst +17 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/PKG-INFO +2 -2
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/__init__.py +2 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/data_selection.py +28 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/discovery.py +33 -1
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/status.py +1 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/pyproject.toml +1 -1
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_discovery.py +176 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/uv.lock +1 -1
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/.editorconfig +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/.github/workflows/ci.yml +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/.github/workflows/release-testpypi.yml +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/.github/workflows/release.yml +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/.gitignore +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/.readthedocs.yaml +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/CONTRIBUTING.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/LICENSE +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/MANIFEST.in +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/Makefile +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/NOTICE +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/README.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/RELEASING.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/base.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/connections.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/discovery.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/discovery_config_libraries.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/discovery_configs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/dmclient.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/exceptions.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/files.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/ifm.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/license.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/__init__.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/connection.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/discovery_config.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/discovery_config_library.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/dm_instance.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/files.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/git.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/ifm.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/license.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/pagination.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/rg_config.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/ruleset.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/ruleset_library.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/runs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/safe_data_preview.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/table_reference.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/user.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/py.typed +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/rg_configs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/ruleset_libraries.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/rulesets.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/runs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/settings.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/spcs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/table_references.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/users.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/Makefile +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/client.models.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/client.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/conf.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/contributing.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/history.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/index.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/installation.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/make.bat +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/modules.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/readme.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/docs/usage.rst +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/__init__.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/conftest.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/helpers.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_base.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_connections.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_discovery_config_libraries.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_discovery_configs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_files.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_ifm.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_license.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_pagination.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_rg_configs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_ruleset_library.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_rulesets.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_runs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_safe_data_preview.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_settings.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_spcs.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_table_references.py +0 -0
- {datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_users.py +0 -0
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
History
|
|
3
3
|
=======
|
|
4
4
|
|
|
5
|
+
1.2.4 (2026-08-12)
|
|
6
|
+
------------------
|
|
7
|
+
|
|
8
|
+
* Added ``rg_config`` to ``ValidationErrorType``, covering ruleset generation config validation errors.
|
|
9
|
+
|
|
10
|
+
Requires server version 3.26.15
|
|
11
|
+
|
|
12
|
+
1.2.3 (2026-08-12)
|
|
13
|
+
------------------
|
|
14
|
+
|
|
15
|
+
* Added file-discovery value counts:
|
|
16
|
+
|
|
17
|
+
* ``value_count`` on ``FileDiscoveryLocatorResult``, the total over the files in the group.
|
|
18
|
+
* ``value_counts`` and ``value_count_status`` on ``FileDiscoveryFile``, typed by ``ValueCountStatus``.
|
|
19
|
+
|
|
20
|
+
Requires server version 3.26.15
|
|
21
|
+
|
|
5
22
|
1.2.2 (2026-07-31)
|
|
6
23
|
------------------
|
|
7
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: datamasque-python
|
|
3
|
-
Version: 1.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/
|
|
@@ -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
|
]
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/data_selection.py
RENAMED
|
@@ -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
|
|
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):
|
|
@@ -31,6 +31,7 @@ from datamasque.client import (
|
|
|
31
31
|
SchemaDiscoveryRequest,
|
|
32
32
|
SchemaDiscoveryResult,
|
|
33
33
|
StringPreview,
|
|
34
|
+
ValueCountStatus,
|
|
34
35
|
)
|
|
35
36
|
from datamasque.client.exceptions import (
|
|
36
37
|
AsyncRulesetGenerationInProgressError,
|
|
@@ -1012,6 +1013,181 @@ def test_file_discovery_result_parses_server_response():
|
|
|
1012
1013
|
assert non_sensitive_match.categories is None
|
|
1013
1014
|
|
|
1014
1015
|
|
|
1016
|
+
def test_file_discovery_value_counts_parse():
|
|
1017
|
+
"""A JSON file's value counts parse, keyed by serialized locator, with the group total on the locator."""
|
|
1018
|
+
result = FileDiscoveryResult.model_validate(
|
|
1019
|
+
{
|
|
1020
|
+
"id": 8,
|
|
1021
|
+
"connection": {"id": "conn-1", "name": "my files"},
|
|
1022
|
+
"file_type": "json",
|
|
1023
|
+
"files": [
|
|
1024
|
+
{
|
|
1025
|
+
"path": "data/staff.json",
|
|
1026
|
+
"file_type": "json",
|
|
1027
|
+
"value_counts": {'["employees","*","email"]': 12},
|
|
1028
|
+
"value_count_status": "counted",
|
|
1029
|
+
}
|
|
1030
|
+
],
|
|
1031
|
+
"results": [
|
|
1032
|
+
{
|
|
1033
|
+
"locator": ["employees", "*", "email"],
|
|
1034
|
+
"data_types": ["string"],
|
|
1035
|
+
"matches": [{"flagged_by": "IDD", "description": "Email", "label": "email"}],
|
|
1036
|
+
"value_count": 30,
|
|
1037
|
+
}
|
|
1038
|
+
],
|
|
1039
|
+
}
|
|
1040
|
+
)
|
|
1041
|
+
|
|
1042
|
+
file = result.files[0]
|
|
1043
|
+
assert file.value_count_status is ValueCountStatus.counted
|
|
1044
|
+
assert file.value_counts == {'["employees","*","email"]': 12}
|
|
1045
|
+
assert result.results[0].value_count == 30
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
def test_file_discovery_uncounted_values_parse():
|
|
1049
|
+
"""A file type that holds no values reports the reason, no counts, and a null count on the locator."""
|
|
1050
|
+
result = FileDiscoveryResult.model_validate(
|
|
1051
|
+
{
|
|
1052
|
+
"id": 9,
|
|
1053
|
+
"connection": {"id": "conn-1", "name": "my files"},
|
|
1054
|
+
"file_type": "csv",
|
|
1055
|
+
"files": [
|
|
1056
|
+
{
|
|
1057
|
+
"path": "data/people.csv",
|
|
1058
|
+
"file_type": "csv",
|
|
1059
|
+
"value_counts": {},
|
|
1060
|
+
"value_count_status": "file_type_has_no_values",
|
|
1061
|
+
}
|
|
1062
|
+
],
|
|
1063
|
+
"results": [
|
|
1064
|
+
{
|
|
1065
|
+
"locator": "email",
|
|
1066
|
+
"data_types": ["string"],
|
|
1067
|
+
"matches": [{"flagged_by": "MDD", "description": "Email", "label": "email"}],
|
|
1068
|
+
"value_count": None,
|
|
1069
|
+
}
|
|
1070
|
+
],
|
|
1071
|
+
}
|
|
1072
|
+
)
|
|
1073
|
+
|
|
1074
|
+
file = result.files[0]
|
|
1075
|
+
assert file.value_count_status is ValueCountStatus.file_type_has_no_values
|
|
1076
|
+
assert file.value_counts == {}
|
|
1077
|
+
assert result.results[0].value_count is None
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
def test_file_discovery_result_without_value_counts_parses():
|
|
1081
|
+
"""A result from a server that predates value counts parses, with a blank status read as `None`."""
|
|
1082
|
+
result = FileDiscoveryResult.model_validate(
|
|
1083
|
+
{
|
|
1084
|
+
"id": 10,
|
|
1085
|
+
"connection": {"id": "conn-1", "name": "my files"},
|
|
1086
|
+
"file_type": "csv",
|
|
1087
|
+
"files": [{"path": "data/people.csv", "file_type": "csv", "value_count_status": ""}],
|
|
1088
|
+
"results": [
|
|
1089
|
+
{
|
|
1090
|
+
"locator": "email",
|
|
1091
|
+
"data_types": ["string"],
|
|
1092
|
+
"matches": [{"flagged_by": "MDD", "description": "Email", "label": "email"}],
|
|
1093
|
+
}
|
|
1094
|
+
],
|
|
1095
|
+
}
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
file = result.files[0]
|
|
1099
|
+
assert file.value_count_status is None
|
|
1100
|
+
assert file.value_counts == {}
|
|
1101
|
+
assert result.results[0].value_count is None
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
def test_file_discovery_value_counts_read_by_locator():
|
|
1105
|
+
"""A file's counts are read with a `Locator`, and listed with each locator in the form the results use."""
|
|
1106
|
+
result = FileDiscoveryResult.model_validate(
|
|
1107
|
+
{
|
|
1108
|
+
"id": 11,
|
|
1109
|
+
"connection": {"id": "conn-1", "name": "my files"},
|
|
1110
|
+
"file_type": "json",
|
|
1111
|
+
"files": [
|
|
1112
|
+
{
|
|
1113
|
+
"path": "data/staff.json",
|
|
1114
|
+
"file_type": "json",
|
|
1115
|
+
"value_counts": {'["employees","*","email"]': 12, '["employees","*","phone"]': 4},
|
|
1116
|
+
"value_count_status": "counted",
|
|
1117
|
+
}
|
|
1118
|
+
],
|
|
1119
|
+
"results": [
|
|
1120
|
+
{
|
|
1121
|
+
"locator": ["employees", "*", "email"],
|
|
1122
|
+
"data_types": ["string"],
|
|
1123
|
+
"matches": [{"flagged_by": "IDD", "description": "Email", "label": "email"}],
|
|
1124
|
+
"value_count": 30,
|
|
1125
|
+
}
|
|
1126
|
+
],
|
|
1127
|
+
}
|
|
1128
|
+
)
|
|
1129
|
+
|
|
1130
|
+
file = result.files[0]
|
|
1131
|
+
assert file.get_value_count_of_locator(result.results[0].locator) == 12
|
|
1132
|
+
assert file.get_value_count_of_locator(["employees", "*", "phone"]) == 4
|
|
1133
|
+
assert file.get_value_count_of_locator(["employees", "*", "address"]) is None
|
|
1134
|
+
assert file.parse_value_counts() == [(["employees", "*", "email"], 12), (["employees", "*", "phone"], 4)]
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
def test_file_discovery_value_count_of_non_ascii_locator():
|
|
1138
|
+
"""A locator with a non-ASCII element matches its key, which the API sends with no escape."""
|
|
1139
|
+
result = FileDiscoveryResult.model_validate(
|
|
1140
|
+
{
|
|
1141
|
+
"id": 13,
|
|
1142
|
+
"connection": {"id": "conn-1", "name": "my files"},
|
|
1143
|
+
"file_type": "json",
|
|
1144
|
+
"files": [
|
|
1145
|
+
{
|
|
1146
|
+
"path": "data/personnel.json",
|
|
1147
|
+
"file_type": "json",
|
|
1148
|
+
"value_counts": {'["personnel","*","prénom"]': 7},
|
|
1149
|
+
"value_count_status": "counted",
|
|
1150
|
+
}
|
|
1151
|
+
],
|
|
1152
|
+
"results": [
|
|
1153
|
+
{
|
|
1154
|
+
"locator": ["personnel", "*", "prénom"],
|
|
1155
|
+
"data_types": ["string"],
|
|
1156
|
+
"matches": [{"flagged_by": "IDD", "description": "First name", "label": "first_name"}],
|
|
1157
|
+
"value_count": 7,
|
|
1158
|
+
}
|
|
1159
|
+
],
|
|
1160
|
+
}
|
|
1161
|
+
)
|
|
1162
|
+
|
|
1163
|
+
file = result.files[0]
|
|
1164
|
+
assert file.get_value_count_of_locator(result.results[0].locator) == 7
|
|
1165
|
+
assert file.parse_value_counts() == [(["personnel", "*", "prénom"], 7)]
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
def test_file_discovery_without_value_counts_reads_no_count():
|
|
1169
|
+
"""A file that carries no counts reports `None` for every locator, and lists nothing."""
|
|
1170
|
+
result = FileDiscoveryResult.model_validate(
|
|
1171
|
+
{
|
|
1172
|
+
"id": 12,
|
|
1173
|
+
"connection": {"id": "conn-1", "name": "my files"},
|
|
1174
|
+
"file_type": "csv",
|
|
1175
|
+
"files": [{"path": "data/people.csv", "file_type": "csv", "value_count_status": ""}],
|
|
1176
|
+
"results": [
|
|
1177
|
+
{
|
|
1178
|
+
"locator": "email",
|
|
1179
|
+
"data_types": ["string"],
|
|
1180
|
+
"matches": [{"flagged_by": "MDD", "description": "Email", "label": "email"}],
|
|
1181
|
+
}
|
|
1182
|
+
],
|
|
1183
|
+
}
|
|
1184
|
+
)
|
|
1185
|
+
|
|
1186
|
+
file = result.files[0]
|
|
1187
|
+
assert file.get_value_count_of_locator("email") is None
|
|
1188
|
+
assert file.parse_value_counts() == []
|
|
1189
|
+
|
|
1190
|
+
|
|
1015
1191
|
def test_file_data_discovery_ignore_rules_serialize():
|
|
1016
1192
|
"""`in_data_discovery.ignore_rules` round-trips into the wire payload."""
|
|
1017
1193
|
req = FileDataDiscoveryRequest(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/discovery_config_libraries.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/discovery_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/ruleset_library.py
RENAMED
|
File without changes
|
|
File without changes
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/safe_data_preview.py
RENAMED
|
File without changes
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/datamasque/client/models/table_reference.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datamasque_python-1.2.2 → datamasque_python-1.2.4}/tests/test_discovery_config_libraries.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|