datamasque-python 1.1.6__tar.gz → 1.1.7__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.1.6 → datamasque_python-1.1.7}/HISTORY.rst +7 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/PKG-INFO +1 -1
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/__init__.py +2 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/connection.py +3 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/ruleset.py +3 -5
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/ruleset_library.py +3 -3
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/status.py +13 -1
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/ruleset_libraries.py +3 -3
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/rulesets.py +2 -3
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/pyproject.toml +1 -1
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/setup.cfg +1 -1
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_connections.py +23 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_ruleset_library.py +14 -11
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_rulesets.py +21 -13
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/uv.lock +1 -1
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/.editorconfig +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/.github/workflows/ci.yml +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/.github/workflows/release-testpypi.yml +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/.github/workflows/release.yml +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/.gitignore +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/.readthedocs.yaml +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/CONTRIBUTING.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/LICENSE +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/MANIFEST.in +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/Makefile +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/NOTICE +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/README.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/base.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/connections.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/discovery.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/discovery_config_libraries.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/discovery_configs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/dmclient.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/exceptions.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/files.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/ifm.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/license.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/__init__.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/data_selection.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/discovery.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/discovery_config.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/discovery_config_library.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/dm_instance.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/files.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/git.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/ifm.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/license.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/pagination.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/runs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/user.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/py.typed +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/runs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/settings.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/spcs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/users.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/Makefile +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/client.models.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/client.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/conf.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/contributing.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/history.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/index.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/installation.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/make.bat +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/modules.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/readme.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/docs/usage.rst +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/__init__.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/conftest.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/helpers.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_base.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_discovery.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_discovery_config_libraries.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_discovery_configs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_files.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_ifm.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_license.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_pagination.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_runs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_settings.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_spcs.py +0 -0
- {datamasque_python-1.1.6 → datamasque_python-1.1.7}/tests/test_users.py +0 -0
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
History
|
|
3
3
|
=======
|
|
4
4
|
|
|
5
|
+
1.1.7 (2026-07-14)
|
|
6
|
+
------------------
|
|
7
|
+
|
|
8
|
+
* Added ``retry_writes`` to ``MongoConnectionConfig`` (default ``True``), serialized only when
|
|
9
|
+
disabled. Set it to ``False`` for AWS DocumentDB, which rejects retryable writes.
|
|
10
|
+
* Updated the validation error API on ``Ruleset`` and ``RulesetLibrary``.
|
|
11
|
+
|
|
5
12
|
1.1.6 (2026-07-13)
|
|
6
13
|
------------------
|
|
7
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datamasque-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.7
|
|
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/
|
|
@@ -119,6 +119,7 @@ from datamasque.client.models.runs import (
|
|
|
119
119
|
from datamasque.client.models.status import (
|
|
120
120
|
AsyncRulesetGenerationTaskStatus,
|
|
121
121
|
MaskingRunStatus,
|
|
122
|
+
ValidationErrorDetails,
|
|
122
123
|
ValidationErrorType,
|
|
123
124
|
ValidationStatus,
|
|
124
125
|
)
|
|
@@ -234,6 +235,7 @@ __all__ = [
|
|
|
234
235
|
"UserId",
|
|
235
236
|
"UserRole",
|
|
236
237
|
"UserSelection",
|
|
238
|
+
"ValidationErrorDetails",
|
|
237
239
|
"ValidationErrorType",
|
|
238
240
|
"ValidationStatus",
|
|
239
241
|
]
|
|
@@ -166,6 +166,7 @@ class MongoConnectionConfig(ConnectionConfig):
|
|
|
166
166
|
tls_ca_file: str = ""
|
|
167
167
|
tls_allow_invalid_certificates: bool = False
|
|
168
168
|
direct_connection: bool = False
|
|
169
|
+
retry_writes: bool = True
|
|
169
170
|
replica_set: str = ""
|
|
170
171
|
is_read_only: bool = False
|
|
171
172
|
|
|
@@ -194,6 +195,8 @@ class MongoConnectionConfig(ConnectionConfig):
|
|
|
194
195
|
d.pop("tls_allow_invalid_certificates", None)
|
|
195
196
|
if not d.get("direct_connection"):
|
|
196
197
|
d.pop("direct_connection", None)
|
|
198
|
+
if d.get("retry_writes", True):
|
|
199
|
+
d.pop("retry_writes", None)
|
|
197
200
|
if not d.get("replica_set"):
|
|
198
201
|
d.pop("replica_set", None)
|
|
199
202
|
if not d.get("user"):
|
|
@@ -4,7 +4,7 @@ from typing import Any, NewType, Optional
|
|
|
4
4
|
from pydantic import Field
|
|
5
5
|
|
|
6
6
|
from datamasque.client.models.git import GitTrackedEntity
|
|
7
|
-
from datamasque.client.models.status import
|
|
7
|
+
from datamasque.client.models.status import ValidationErrorDetails, ValidationStatus
|
|
8
8
|
|
|
9
9
|
RulesetId = NewType("RulesetId", str)
|
|
10
10
|
|
|
@@ -44,7 +44,5 @@ class Ruleset(GitTrackedEntity):
|
|
|
44
44
|
# Server-populated read-only fields, excluded from request bodies.
|
|
45
45
|
id: Optional[RulesetId] = Field(default=None, exclude=True)
|
|
46
46
|
is_valid: Optional[ValidationStatus] = Field(default=None, exclude=True)
|
|
47
|
-
|
|
48
|
-
"""
|
|
49
|
-
validation_error_type: Optional[ValidationErrorType] = Field(default=None, exclude=True)
|
|
50
|
-
"""Category of the validation failure, or `None` when valid."""
|
|
47
|
+
validation_errors: list[ValidationErrorDetails] = Field(default_factory=list, exclude=True)
|
|
48
|
+
"""Validation errors surfaced by the server; empty when valid."""
|
{datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/ruleset_library.py
RENAMED
|
@@ -4,7 +4,7 @@ from typing import NewType, Optional
|
|
|
4
4
|
from pydantic import Field
|
|
5
5
|
|
|
6
6
|
from datamasque.client.models.git import GitTrackedEntity
|
|
7
|
-
from datamasque.client.models.status import ValidationStatus
|
|
7
|
+
from datamasque.client.models.status import ValidationErrorDetails, ValidationStatus
|
|
8
8
|
|
|
9
9
|
RulesetLibraryId = NewType("RulesetLibraryId", str)
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ class RulesetLibrary(GitTrackedEntity):
|
|
|
19
19
|
# Server-populated read-only fields, excluded from request bodies.
|
|
20
20
|
id: Optional[RulesetLibraryId] = Field(default=None, exclude=True)
|
|
21
21
|
is_valid: Optional[ValidationStatus] = Field(default=None, exclude=True)
|
|
22
|
-
|
|
23
|
-
"""
|
|
22
|
+
validation_errors: list[ValidationErrorDetails] = Field(default_factory=list, exclude=True)
|
|
23
|
+
"""Validation errors surfaced by the server; empty when valid."""
|
|
24
24
|
created: Optional[datetime] = Field(default=None, exclude=True)
|
|
25
25
|
modified: Optional[datetime] = Field(default=None, exclude=True)
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import enum
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
2
5
|
|
|
3
6
|
|
|
4
7
|
class ValidationStatus(enum.Enum):
|
|
@@ -11,7 +14,7 @@ class ValidationStatus(enum.Enum):
|
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
class ValidationErrorType(enum.Enum):
|
|
14
|
-
"""Categorises why
|
|
17
|
+
"""Categorises why validation failed (see `ValidationErrorDetails.validation_error_type`)."""
|
|
15
18
|
|
|
16
19
|
ruleset = "ruleset"
|
|
17
20
|
library_missing = "library_missing"
|
|
@@ -19,6 +22,15 @@ class ValidationErrorType(enum.Enum):
|
|
|
19
22
|
expansion = "expansion" # The ruleset is not valid once its library references are expanded.
|
|
20
23
|
|
|
21
24
|
|
|
25
|
+
class ValidationErrorDetails(BaseModel):
|
|
26
|
+
"""A single validation error, with its position in the YAML when available."""
|
|
27
|
+
|
|
28
|
+
message: str
|
|
29
|
+
validation_error_type: Optional[ValidationErrorType] = None
|
|
30
|
+
line_number: Optional[int] = None
|
|
31
|
+
column_number: Optional[int] = None
|
|
32
|
+
|
|
33
|
+
|
|
22
34
|
class MaskingRunStatus(enum.Enum):
|
|
23
35
|
"""List of valid masking run statuses."""
|
|
24
36
|
|
|
@@ -64,7 +64,7 @@ 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`, `
|
|
67
|
+
(`id`, `is_valid`, `validation_errors`, `git`, `created`, `modified`) and returns the library.
|
|
68
68
|
"""
|
|
69
69
|
|
|
70
70
|
data = library.model_dump(exclude_none=True, by_alias=True, mode="json")
|
|
@@ -72,7 +72,7 @@ class RulesetLibraryClient(BaseClient):
|
|
|
72
72
|
created_library = RulesetLibrary.model_validate(response.json())
|
|
73
73
|
library.id = created_library.id
|
|
74
74
|
library.is_valid = created_library.is_valid
|
|
75
|
-
library.
|
|
75
|
+
library.validation_errors = created_library.validation_errors
|
|
76
76
|
library.git = created_library.git
|
|
77
77
|
library.created = created_library.created
|
|
78
78
|
library.modified = created_library.modified
|
|
@@ -93,7 +93,7 @@ class RulesetLibraryClient(BaseClient):
|
|
|
93
93
|
response = self.make_request("PUT", f"/api/ruleset-libraries/{library.id}/", data=data)
|
|
94
94
|
updated_library = RulesetLibrary.model_validate(response.json())
|
|
95
95
|
library.is_valid = updated_library.is_valid
|
|
96
|
-
library.
|
|
96
|
+
library.validation_errors = updated_library.validation_errors
|
|
97
97
|
library.git = updated_library.git
|
|
98
98
|
library.modified = updated_library.modified
|
|
99
99
|
logger.debug('Update of ruleset library "%s" successful', library.name)
|
|
@@ -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`, `
|
|
23
|
+
Populates the given ruleset's `id`, `is_valid`, `validation_errors`,
|
|
24
24
|
and `git` fields from the server response, and returns the same ruleset instance for convenience.
|
|
25
25
|
"""
|
|
26
26
|
|
|
@@ -29,8 +29,7 @@ class RulesetClient(BaseClient):
|
|
|
29
29
|
created = Ruleset.model_validate(response.json())
|
|
30
30
|
ruleset.id = created.id
|
|
31
31
|
ruleset.is_valid = created.is_valid
|
|
32
|
-
ruleset.
|
|
33
|
-
ruleset.validation_error_type = created.validation_error_type
|
|
32
|
+
ruleset.validation_errors = created.validation_errors
|
|
34
33
|
ruleset.git = created.git
|
|
35
34
|
|
|
36
35
|
if response.status_code == 201:
|
|
@@ -1169,6 +1169,29 @@ def test_mongo_connection_model_dump_omits_falsy_optional_flags():
|
|
|
1169
1169
|
assert absent not in api_dict
|
|
1170
1170
|
|
|
1171
1171
|
|
|
1172
|
+
def test_mongo_connection_retry_writes_defaults_true_and_is_omitted():
|
|
1173
|
+
"""retry_writes defaults to True (matching the server default), so it is left out of the payload."""
|
|
1174
|
+
conn = MongoConnectionConfig(name="mongo", host="mongo.example", database="people")
|
|
1175
|
+
assert conn.retry_writes is True
|
|
1176
|
+
api_dict = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
|
|
1177
|
+
assert "retry_writes" not in api_dict
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
def test_mongo_connection_sends_retry_writes_when_disabled():
|
|
1181
|
+
"""retry_writes is sent only when explicitly disabled (e.g. AWS DocumentDB rejects retryable writes)."""
|
|
1182
|
+
conn = MongoConnectionConfig(name="mongo", host="mongo.example", database="people", retry_writes=False)
|
|
1183
|
+
api_dict = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
|
|
1184
|
+
assert api_dict["retry_writes"] is False
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
def test_documentdb_connection_sends_retry_writes_when_disabled():
|
|
1188
|
+
"""A DocumentDB connection inherits retry_writes and sends it when disabled."""
|
|
1189
|
+
conn = DocumentDbConnectionConfig(name="docdb", host="docdb.example", database="people", retry_writes=False)
|
|
1190
|
+
api_dict = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
|
|
1191
|
+
assert api_dict["db_type"] == "documentdb"
|
|
1192
|
+
assert api_dict["retry_writes"] is False
|
|
1193
|
+
|
|
1194
|
+
|
|
1172
1195
|
def test_mongo_connection_model_validate_blanks_encrypted_password():
|
|
1173
1196
|
payload = {
|
|
1174
1197
|
"id": "mongo-id-1",
|
|
@@ -14,6 +14,7 @@ from datamasque.client.models.ruleset_library import (
|
|
|
14
14
|
RulesetLibraryId,
|
|
15
15
|
ValidationStatus,
|
|
16
16
|
)
|
|
17
|
+
from datamasque.client.models.status import ValidationErrorDetails
|
|
17
18
|
|
|
18
19
|
LIBRARY_ID_1 = "aaaaaaaa-1111-2222-3333-444444444444"
|
|
19
20
|
LIBRARY_ID_2 = "bbbbbbbb-1111-2222-3333-444444444444"
|
|
@@ -618,17 +619,17 @@ def test_list_rulesets_using_library_pagination(client: DataMasqueClient) -> Non
|
|
|
618
619
|
assert rulesets[2].name == "r3"
|
|
619
620
|
|
|
620
621
|
|
|
621
|
-
def
|
|
622
|
+
def test_create_ruleset_library_populates_validation_errors(
|
|
622
623
|
client: DataMasqueClient, ruleset_library: RulesetLibrary
|
|
623
624
|
) -> None:
|
|
624
|
-
"""The server's `
|
|
625
|
+
"""The server's `validation_errors` list is surfaced on the returned library."""
|
|
625
626
|
create_response = {
|
|
626
627
|
"id": LIBRARY_ID_1,
|
|
627
628
|
"name": "test_library",
|
|
628
629
|
"namespace": "test_ns",
|
|
629
630
|
"config_yaml": "version: '1.0'\nfunctions: []",
|
|
630
631
|
"is_valid": "invalid",
|
|
631
|
-
"
|
|
632
|
+
"validation_errors": [{"message": "Invalid function definition"}],
|
|
632
633
|
"created": "2025-06-01T10:00:00Z",
|
|
633
634
|
"modified": "2025-06-01T10:00:00Z",
|
|
634
635
|
}
|
|
@@ -641,13 +642,14 @@ def test_create_ruleset_library_populates_validation_error(
|
|
|
641
642
|
)
|
|
642
643
|
result = client.create_ruleset_library(ruleset_library)
|
|
643
644
|
|
|
644
|
-
assert result.
|
|
645
|
+
assert len(result.validation_errors) == 1
|
|
646
|
+
assert result.validation_errors[0].message == "Invalid function definition"
|
|
645
647
|
|
|
646
648
|
|
|
647
|
-
def
|
|
649
|
+
def test_update_ruleset_library_populates_validation_errors(
|
|
648
650
|
client: DataMasqueClient, ruleset_library: RulesetLibrary
|
|
649
651
|
) -> None:
|
|
650
|
-
"""A full update also surfaces the server's `
|
|
652
|
+
"""A full update also surfaces the server's `validation_errors` list."""
|
|
651
653
|
ruleset_library.id = RulesetLibraryId(LIBRARY_ID_1)
|
|
652
654
|
update_response = {
|
|
653
655
|
"id": LIBRARY_ID_1,
|
|
@@ -655,7 +657,7 @@ def test_update_ruleset_library_populates_validation_error(
|
|
|
655
657
|
"namespace": "test_ns",
|
|
656
658
|
"config_yaml": "version: '1.0'\nfunctions: []",
|
|
657
659
|
"is_valid": "invalid",
|
|
658
|
-
"
|
|
660
|
+
"validation_errors": [{"message": "Invalid function definition"}],
|
|
659
661
|
"created": "2025-06-01T10:00:00Z",
|
|
660
662
|
"modified": "2025-06-02T10:00:00Z",
|
|
661
663
|
}
|
|
@@ -668,7 +670,8 @@ def test_update_ruleset_library_populates_validation_error(
|
|
|
668
670
|
)
|
|
669
671
|
result = client.update_ruleset_library(ruleset_library)
|
|
670
672
|
|
|
671
|
-
assert result.
|
|
673
|
+
assert len(result.validation_errors) == 1
|
|
674
|
+
assert result.validation_errors[0].message == "Invalid function definition"
|
|
672
675
|
|
|
673
676
|
|
|
674
677
|
def test_create_ruleset_library_does_not_send_read_only_fields(
|
|
@@ -677,14 +680,14 @@ def test_create_ruleset_library_does_not_send_read_only_fields(
|
|
|
677
680
|
"""Read-only server fields must never appear in the create request body."""
|
|
678
681
|
ruleset_library.id = RulesetLibraryId(LIBRARY_ID_1)
|
|
679
682
|
ruleset_library.is_valid = ValidationStatus.invalid
|
|
680
|
-
ruleset_library.
|
|
683
|
+
ruleset_library.validation_errors = [ValidationErrorDetails(message="stale error")]
|
|
681
684
|
create_response = {
|
|
682
685
|
"id": LIBRARY_ID_1,
|
|
683
686
|
"name": "test_library",
|
|
684
687
|
"namespace": "test_ns",
|
|
685
688
|
"config_yaml": "version: '1.0'\nfunctions: []",
|
|
686
689
|
"is_valid": "invalid",
|
|
687
|
-
"
|
|
690
|
+
"validation_errors": [{"message": "Invalid function definition"}],
|
|
688
691
|
"created": "2025-06-01T10:00:00Z",
|
|
689
692
|
"modified": "2025-06-01T10:00:00Z",
|
|
690
693
|
}
|
|
@@ -698,7 +701,7 @@ def test_create_ruleset_library_does_not_send_read_only_fields(
|
|
|
698
701
|
client.create_ruleset_library(ruleset_library)
|
|
699
702
|
|
|
700
703
|
body = m.last_request.json()
|
|
701
|
-
for read_only_field in ("id", "is_valid", "
|
|
704
|
+
for read_only_field in ("id", "is_valid", "validation_errors", "created", "modified"):
|
|
702
705
|
assert read_only_field not in body
|
|
703
706
|
# Input fields are still present.
|
|
704
707
|
assert body["name"] == "test_library"
|
|
@@ -134,8 +134,8 @@ def test_delete_ruleset_that_does_not_exist(client, existing_rulesets_json):
|
|
|
134
134
|
assert m.request_history[0].method == "GET"
|
|
135
135
|
|
|
136
136
|
|
|
137
|
-
def
|
|
138
|
-
"""The server's `
|
|
137
|
+
def test_create_or_update_ruleset_populates_validation_errors(client, ruleset):
|
|
138
|
+
"""The server's `validation_errors` list is surfaced on the returned ruleset."""
|
|
139
139
|
with requests_mock.Mocker() as m:
|
|
140
140
|
m.post(
|
|
141
141
|
"http://test-server/api/rulesets/?upsert=true",
|
|
@@ -143,19 +143,29 @@ def test_create_or_update_ruleset_populates_validation_error(client, ruleset):
|
|
|
143
143
|
"id": "2",
|
|
144
144
|
"name": "test_ruleset",
|
|
145
145
|
"is_valid": "invalid",
|
|
146
|
-
"
|
|
147
|
-
|
|
146
|
+
"validation_errors": [
|
|
147
|
+
{
|
|
148
|
+
"message": "Missing required field: table",
|
|
149
|
+
"validation_error_type": "ruleset",
|
|
150
|
+
"line_number": 5,
|
|
151
|
+
"column_number": 3,
|
|
152
|
+
}
|
|
153
|
+
],
|
|
148
154
|
},
|
|
149
155
|
status_code=201,
|
|
150
156
|
)
|
|
151
157
|
result = client.create_or_update_ruleset(ruleset)
|
|
152
158
|
|
|
153
|
-
assert result.
|
|
154
|
-
|
|
159
|
+
assert len(result.validation_errors) == 1
|
|
160
|
+
error = result.validation_errors[0]
|
|
161
|
+
assert error.message == "Missing required field: table"
|
|
162
|
+
assert error.validation_error_type is ValidationErrorType.ruleset
|
|
163
|
+
assert error.line_number == 5
|
|
164
|
+
assert error.column_number == 3
|
|
155
165
|
|
|
156
166
|
|
|
157
|
-
def
|
|
158
|
-
"""`
|
|
167
|
+
def test_create_or_update_ruleset_validation_errors_empty_when_valid(client, ruleset):
|
|
168
|
+
"""`validation_errors` is empty when the server omits it (a valid ruleset)."""
|
|
159
169
|
with requests_mock.Mocker() as m:
|
|
160
170
|
m.post(
|
|
161
171
|
"http://test-server/api/rulesets/?upsert=true",
|
|
@@ -164,8 +174,7 @@ def test_create_or_update_ruleset_validation_error_none_when_absent(client, rule
|
|
|
164
174
|
)
|
|
165
175
|
result = client.create_or_update_ruleset(ruleset)
|
|
166
176
|
|
|
167
|
-
assert result.
|
|
168
|
-
assert result.validation_error_type is None
|
|
177
|
+
assert result.validation_errors == []
|
|
169
178
|
|
|
170
179
|
|
|
171
180
|
def test_create_or_update_ruleset_does_not_send_read_only_fields(client, ruleset):
|
|
@@ -177,8 +186,7 @@ def test_create_or_update_ruleset_does_not_send_read_only_fields(client, ruleset
|
|
|
177
186
|
"id": "2",
|
|
178
187
|
"name": "test_ruleset",
|
|
179
188
|
"is_valid": "invalid",
|
|
180
|
-
"
|
|
181
|
-
"validation_error_type": "ruleset",
|
|
189
|
+
"validation_errors": [{"message": "bad", "validation_error_type": "ruleset"}],
|
|
182
190
|
},
|
|
183
191
|
status_code=201,
|
|
184
192
|
)
|
|
@@ -188,7 +196,7 @@ def test_create_or_update_ruleset_does_not_send_read_only_fields(client, ruleset
|
|
|
188
196
|
client.create_or_update_ruleset(ruleset)
|
|
189
197
|
|
|
190
198
|
body = m.last_request.json()
|
|
191
|
-
for read_only_field in ("id", "is_valid", "
|
|
199
|
+
for read_only_field in ("id", "is_valid", "validation_errors"):
|
|
192
200
|
assert read_only_field not in body
|
|
193
201
|
# Input fields are still present.
|
|
194
202
|
assert body["config_yaml"] == "version: '1.0'\ntasks: []"
|
|
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.1.6 → datamasque_python-1.1.7}/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
|
{datamasque_python-1.1.6 → datamasque_python-1.1.7}/datamasque/client/models/data_selection.py
RENAMED
|
File without changes
|
|
File without changes
|
{datamasque_python-1.1.6 → datamasque_python-1.1.7}/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
|
|
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.1.6 → datamasque_python-1.1.7}/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
|