datamasque-python 1.1.1__tar.gz → 1.1.2__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.1 → datamasque_python-1.1.2}/HISTORY.rst +6 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/PKG-INFO +1 -1
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/discovery.py +6 -2
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/status.py +14 -1
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/pyproject.toml +1 -1
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/setup.cfg +1 -1
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_discovery.py +56 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/uv.lock +1 -1
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/.editorconfig +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/.github/workflows/ci.yml +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/.github/workflows/release-testpypi.yml +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/.github/workflows/release.yml +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/.gitignore +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/.readthedocs.yaml +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/CONTRIBUTING.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/LICENSE +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/MANIFEST.in +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/Makefile +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/NOTICE +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/README.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/__init__.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/base.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/connections.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/discovery_configs.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/dmclient.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/exceptions.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/files.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/ifm.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/license.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/__init__.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/connection.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/data_selection.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/discovery.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/discovery_config.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/dm_instance.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/files.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/git.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/ifm.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/license.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/pagination.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/ruleset.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/ruleset_library.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/runs.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/user.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/py.typed +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/ruleset_libraries.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/rulesets.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/runs.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/settings.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/users.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/Makefile +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/client.models.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/client.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/conf.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/contributing.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/history.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/index.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/installation.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/make.bat +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/modules.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/readme.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/docs/usage.rst +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/__init__.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/conftest.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/helpers.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_base.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_connections.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_discovery_configs.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_files.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_ifm.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_license.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_pagination.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_ruleset_library.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_rulesets.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_runs.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_settings.py +0 -0
- {datamasque_python-1.1.1 → datamasque_python-1.1.2}/tests/test_users.py +0 -0
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
History
|
|
3
3
|
=======
|
|
4
4
|
|
|
5
|
+
1.1.2 (2026-06-26)
|
|
6
|
+
------------------
|
|
7
|
+
|
|
8
|
+
* Completed wiring of the ``finished_with_warnings`` status for ``AsyncRulesetGenerationTaskStatus``.
|
|
9
|
+
* Added the ``cancelled`` status to ``AsyncRulesetGenerationTaskStatus``.
|
|
10
|
+
|
|
5
11
|
1.1.1 (2026-06-25)
|
|
6
12
|
------------------
|
|
7
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datamasque-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.2
|
|
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/
|
|
@@ -166,7 +166,7 @@ class DiscoveryClient(BaseClient):
|
|
|
166
166
|
returns a list containing one ruleset
|
|
167
167
|
|
|
168
168
|
Raises `AsyncRulesetGenerationInProgressError` if the task hasn't finished yet,
|
|
169
|
-
and `DataMasqueException` if it failed.
|
|
169
|
+
and `DataMasqueException` if it failed or was cancelled.
|
|
170
170
|
|
|
171
171
|
Note that the ruleset(s) have autogenerated names, which you may want to customize before uploading.
|
|
172
172
|
"""
|
|
@@ -176,7 +176,11 @@ class DiscoveryClient(BaseClient):
|
|
|
176
176
|
logger.error("Ruleset generation failed for connection: %s", connection_id)
|
|
177
177
|
raise DataMasqueException(f"Ruleset generation failed for connection: {connection_id}")
|
|
178
178
|
|
|
179
|
-
if status is
|
|
179
|
+
if status is AsyncRulesetGenerationTaskStatus.cancelled:
|
|
180
|
+
logger.error("Ruleset generation was cancelled for connection: %s", connection_id)
|
|
181
|
+
raise DataMasqueException(f"Ruleset generation was cancelled for connection: {connection_id}")
|
|
182
|
+
|
|
183
|
+
if not status.is_finished:
|
|
180
184
|
logger.error(
|
|
181
185
|
"Ruleset generation is still in progress for connection: %s. Status: `%s`",
|
|
182
186
|
connection_id,
|
|
@@ -64,15 +64,28 @@ class AsyncRulesetGenerationTaskStatus(enum.Enum):
|
|
|
64
64
|
failed = "failed"
|
|
65
65
|
running = "running"
|
|
66
66
|
queued = "queued"
|
|
67
|
+
cancelled = "cancelled"
|
|
67
68
|
|
|
68
69
|
@classmethod
|
|
69
70
|
def get_final_states(cls) -> set["AsyncRulesetGenerationTaskStatus"]:
|
|
70
71
|
"""Returns the list of final statuses, i.e. the ruleset generation has completed, successfully or otherwise."""
|
|
71
72
|
|
|
72
|
-
return {cls.finished, cls.failed}
|
|
73
|
+
return {cls.finished, cls.finished_with_warnings, cls.failed, cls.cancelled}
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def get_finished_states(cls) -> set["AsyncRulesetGenerationTaskStatus"]:
|
|
77
|
+
"""Returns the list of statuses that indicate the ruleset generation completed successfully."""
|
|
78
|
+
|
|
79
|
+
return {cls.finished, cls.finished_with_warnings}
|
|
73
80
|
|
|
74
81
|
@property
|
|
75
82
|
def is_in_final_state(self) -> bool:
|
|
76
83
|
"""Returns True if this status is a final status."""
|
|
77
84
|
|
|
78
85
|
return self in self.get_final_states()
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def is_finished(self) -> bool:
|
|
89
|
+
"""Returns True if this status is a finished status."""
|
|
90
|
+
|
|
91
|
+
return self in self.get_finished_states()
|
|
@@ -204,6 +204,47 @@ def test_get_generated_rulesets_success(client):
|
|
|
204
204
|
assert rulesets[1].yaml == yaml_content_2.decode("utf-8")
|
|
205
205
|
|
|
206
206
|
|
|
207
|
+
def test_get_generated_rulesets_finished_with_warnings_success(client):
|
|
208
|
+
"""A task that finishes with warnings is still successful: its rulesets are returned, not treated as in-progress."""
|
|
209
|
+
connection_id = ConnectionId("1")
|
|
210
|
+
yaml_content = b"""
|
|
211
|
+
version: "1.0"
|
|
212
|
+
tasks:
|
|
213
|
+
- type: mask_table
|
|
214
|
+
table: table1
|
|
215
|
+
key: id
|
|
216
|
+
rules:
|
|
217
|
+
- column: col1
|
|
218
|
+
masks:
|
|
219
|
+
- type: do_nothing
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
with requests_mock.Mocker() as m:
|
|
223
|
+
m.get(
|
|
224
|
+
f"http://test-server/api/async-generate-ruleset/{connection_id}/",
|
|
225
|
+
json={"status": "finished_with_warnings"},
|
|
226
|
+
status_code=200,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
zip_buffer = BytesIO()
|
|
230
|
+
with zipfile.ZipFile(zip_buffer, "w") as zip_file:
|
|
231
|
+
zip_file.writestr("ruleset1.yml", yaml_content.decode("utf-8"))
|
|
232
|
+
zip_buffer.seek(0)
|
|
233
|
+
|
|
234
|
+
m.get(
|
|
235
|
+
f"http://test-server/api/async-generate-ruleset/{connection_id}/download-rulesets/",
|
|
236
|
+
content=zip_buffer.getvalue(),
|
|
237
|
+
headers={"Content-Disposition": 'attachment; filename="rulesets.zip"'},
|
|
238
|
+
status_code=200,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
rulesets = client.get_generated_rulesets(connection_id)
|
|
242
|
+
|
|
243
|
+
assert len(rulesets) == 1
|
|
244
|
+
assert rulesets[0].name == "ruleset1"
|
|
245
|
+
assert rulesets[0].yaml == yaml_content.decode("utf-8")
|
|
246
|
+
|
|
247
|
+
|
|
207
248
|
def test_get_generated_rulesets_empty_archive_raises(client):
|
|
208
249
|
"""A finished task whose download archive contains no ruleset files raises a clear error."""
|
|
209
250
|
connection_id = ConnectionId("1")
|
|
@@ -290,6 +331,21 @@ def test_get_generated_rulesets_failed(client):
|
|
|
290
331
|
client.get_generated_rulesets(connection_id)
|
|
291
332
|
|
|
292
333
|
|
|
334
|
+
def test_get_generated_rulesets_cancelled(client):
|
|
335
|
+
"""A cancelled task is terminal, so it raises a non-retryable DataMasqueException, not the in-progress error."""
|
|
336
|
+
connection_id = ConnectionId("1")
|
|
337
|
+
|
|
338
|
+
with requests_mock.Mocker() as m:
|
|
339
|
+
m.get(
|
|
340
|
+
f"http://test-server/api/async-generate-ruleset/{connection_id}/",
|
|
341
|
+
json={"status": "cancelled"},
|
|
342
|
+
status_code=200,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
with pytest.raises(DataMasqueException, match="Ruleset generation was cancelled for connection"):
|
|
346
|
+
client.get_generated_rulesets(connection_id)
|
|
347
|
+
|
|
348
|
+
|
|
293
349
|
def test_get_generated_rulesets_in_progress(client):
|
|
294
350
|
connection_id = ConnectionId("1")
|
|
295
351
|
|
|
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.1 → datamasque_python-1.1.2}/datamasque/client/models/data_selection.py
RENAMED
|
File without changes
|
|
File without changes
|
{datamasque_python-1.1.1 → datamasque_python-1.1.2}/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
|
{datamasque_python-1.1.1 → datamasque_python-1.1.2}/datamasque/client/models/ruleset_library.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|