diff --git a/dataconnect/models.py b/dataconnect/models.py index d96a4e1..af696a5 100644 --- a/dataconnect/models.py +++ b/dataconnect/models.py @@ -146,6 +146,8 @@ class _PublishEnvelopeResult: checks: ResultChecks = field(default_factory=ResultChecks) errors: list[str] = field(default_factory=list) invalid_records: pd.DataFrame | None = None + blinding_status: str | None = None + warnings: list[str] = field(default_factory=list) # Flat accessors below are deprecated views onto the envelope, kept so # existing notebooks keep working. Prefer metadata/metrics/checks. diff --git a/dataconnect/service/mappers.py b/dataconnect/service/mappers.py index 6d56ef9..66bae58 100644 --- a/dataconnect/service/mappers.py +++ b/dataconnect/service/mappers.py @@ -147,6 +147,8 @@ def _envelope_to_domain(envelope: PublishEnvelope, result_cls: type[_ResultT]) - ), errors=envelope.errors, invalid_records=envelope.invalid_records, + blinding_status=envelope.blinding_status, + warnings=envelope.warnings, ) diff --git a/dataconnect/transport/models.py b/dataconnect/transport/models.py index 5befc2d..9dbc9e8 100644 --- a/dataconnect/transport/models.py +++ b/dataconnect/transport/models.py @@ -143,6 +143,8 @@ class PublishEnvelope: errors: list[str] = field(default_factory=list) invalid_records: pd.DataFrame | None = None """Populated from the Arrow IPC channel, not from the JSON payload.""" + blinding_status: str | None = None + warnings: list[str] = field(default_factory=list) @classmethod def from_json(cls, payload: dict, invalid_records: pd.DataFrame | None = None) -> PublishEnvelope: @@ -178,6 +180,8 @@ def from_json(cls, payload: dict, invalid_records: pd.DataFrame | None = None) - ), errors=payload.get("errors") or [], invalid_records=invalid_records, + blinding_status=payload.get("blinding_status"), + warnings=payload.get("warnings") or [], ) diff --git a/tests/test_dry_publish.py b/tests/test_dry_publish.py index 86ca44d..61e35de 100644 --- a/tests/test_dry_publish.py +++ b/tests/test_dry_publish.py @@ -62,6 +62,8 @@ def _make_dry_publish_response(**overrides: object) -> DryPublishResponse: "duplicate_record_count": 0, "invalid_record_count": 0, "invalid_records": None, + "blinding_status": None, + "warnings": [], **overrides, } return DryPublishResponse( @@ -85,6 +87,8 @@ def _make_dry_publish_response(**overrides: object) -> DryPublishResponse: ), errors=flat["errors"], invalid_records=flat["invalid_records"], + blinding_status=flat["blinding_status"], + warnings=flat["warnings"], ) @@ -230,6 +234,24 @@ def test_trace_id_is_not_added_to_result_contract(self) -> None: result = dry_publish_response_to_domain(_make_dry_publish_response()) assert not hasattr(result, "trace_id") + def test_blinding_status_mapped(self) -> None: + result = dry_publish_response_to_domain(_make_dry_publish_response(blinding_status="UNBLINDING")) + assert result.blinding_status == "UNBLINDING" + + def test_warnings_list_mapped_without_conversion_to_errors(self) -> None: + warnings = ["Prior version had a different key column", "Source dataset pending blinding review"] + result = dry_publish_response_to_domain(_make_dry_publish_response(warnings=warnings)) + assert result.warnings == warnings + assert result.errors == [] + + def test_blinding_status_defaults_to_none_when_omitted(self) -> None: + result = dry_publish_response_to_domain(_make_dry_publish_response()) + assert result.blinding_status is None + + def test_warnings_defaults_to_empty_list_when_omitted(self) -> None: + result = dry_publish_response_to_domain(_make_dry_publish_response()) + assert result.warnings == [] + # --------------------------------------------------------------------------- # DefaultDataConnectService.dry_publish @@ -542,6 +564,25 @@ def test_errors_list_parsed_from_json(self) -> None: result = transport.dry_publish_dataset(PublishRequest(input_config="{}", data=pd.DataFrame({"x": [1]}))) assert result.errors == ["err1", "err2"] + def test_blinding_fields_default_when_omitted_from_legacy_json(self) -> None: + transport = _make_flight_transport() + _wire_do_put(transport, _VALID_JSON_RESP) # no blinding_status/warnings keys + + result = transport.dry_publish_dataset(PublishRequest(input_config="{}", data=pd.DataFrame({"x": [1]}))) + assert result.blinding_status is None + assert result.warnings == [] + + def test_blinding_fields_parsed_from_json_when_present(self) -> None: + transport = _make_flight_transport() + _wire_do_put( + transport, + {**_VALID_JSON_RESP, "blinding_status": "UNBLINDING", "warnings": ["w1", "w2"]}, + ) + + result = transport.dry_publish_dataset(PublishRequest(input_config="{}", data=pd.DataFrame({"x": [1]}))) + assert result.blinding_status == "UNBLINDING" + assert result.warnings == ["w1", "w2"] + def test_none_ipc_buf_yields_no_invalid_records(self) -> None: transport = _make_flight_transport() # Second reader.read() returns None — server sent no invalid-records table