Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions pyrit/models/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,27 +169,29 @@ class Parameter(BaseModel):
@classmethod
def _reconstruct_param_type_from_wire(cls, data: Any) -> Any:
"""
Rebuild the live ``param_type`` when validating from a serialized payload.
Restore live parameter metadata from a serialized payload.

Serialization drops the live ``param_type`` and projects it onto the
display fields ``type_name`` / ``choices`` / ``is_list``. A client that
deserializes the wire form (e.g. the CLI consuming the REST catalog) has
those fields but no live type; this reconstructs a coercion-capable
``param_type`` from them so the round-tripped ``Parameter`` can still
coerce and validate values. In-process construction (which already
supplies a live ``param_type``, or supplies neither) is left untouched.
coerce and validate values. The wire form also distinguishes a required
default from an optional null default using the ``required`` flag.

Returns:
Any: The input unchanged, or a copy with ``param_type`` reconstructed
from the serialized display fields.
Any: The input unchanged, or a copy with live metadata restored.
"""
if not isinstance(data, dict):
return data
needs_param_type = data.get("param_type") is None and "type_name" in data
needs_reference = data.get("reference") is None and data.get("reference_type") is not None
if not needs_param_type and not needs_reference:
needs_required_default = data.get("required") is True and data.get("default") is None
if not (needs_param_type or needs_reference or needs_required_default):
return data
data = dict(data)
if needs_required_default:
data["default"] = REQUIRED_VALUE
if needs_param_type:
data["param_type"] = _param_type_from_display(
type_name=data.get("type_name"),
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/models/test_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,16 @@ def test_required_default_serializes_to_none(self) -> None:
assert dumped["type_name"] == "str"
assert dumped["choices"] == ["a", "b"]

@pytest.mark.parametrize("default", [REQUIRED_VALUE, None])
def test_required_status_round_trips(self, default: object) -> None:
original = Parameter(name="count", description="d", param_type=int, default=default)

restored = Parameter.model_validate_json(original.model_dump_json())

assert restored.required is original.required
assert restored.default is default
assert restored.coerce_value("5") == 5

def test_enum_default_serializes_to_member_value(self) -> None:
dumped = Parameter(name="speed", description="d", default=_Speed.FAST, param_type=_Speed).model_dump()

Expand Down
Loading