Skip to content

Commit

Permalink
feat(api): Allow omitting description and display_color from `Pro…
Browse files Browse the repository at this point in the history
…tocolContext.define_liquid()` (#15906)
  • Loading branch information
SyntaxColoring authored Aug 7, 2024
1 parent 4c3305a commit 837d5ae
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 6 deletions.
5 changes: 5 additions & 0 deletions api/docs/v2/versioning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ This table lists the correspondence between Protocol API versions and robot soft
Changes in API Versions
=======================

Version 2.20
------------

- You can now call :py:obj:`.ProtocolContext.define_liquid()` without supplying a ``description`` or ``display_color``.

Version 2.19
------------

Expand Down
53 changes: 50 additions & 3 deletions api/src/opentrons/protocol_api/protocol_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@
]


class _Unset:
"""A sentinel value for when no value has been supplied for an argument,
when `None` is already taken for some other meaning.
User code should never use this explicitly.
"""

pass


class ProtocolContext(CommandPublisher):
"""A context for the state of a protocol.
Expand Down Expand Up @@ -1197,17 +1207,54 @@ def set_rail_lights(self, on: bool) -> None:

@requires_version(2, 14)
def define_liquid(
self, name: str, description: Optional[str], display_color: Optional[str]
self,
name: str,
description: Union[str, None, _Unset] = _Unset(),
display_color: Union[str, None, _Unset] = _Unset(),
) -> Liquid:
# This first line of the docstring overrides the method signature in our public
# docs, which would otherwise have the `_Unset()`s expanded to a bunch of junk.
"""
define_liquid(self, name: str, description: Optional[str] = None, display_color: Optional[str] = None)
Define a liquid within a protocol.
:param str name: A human-readable name for the liquid.
:param str description: An optional description of the liquid.
:param str display_color: An optional hex color code, with hash included, to represent the specified liquid. Standard three-value, four-value, six-value, and eight-value syntax are all acceptable.
:param Optional[str] description: An optional description of the liquid.
:param Optional[str] display_color: An optional hex color code, with hash included,
to represent the specified liquid. For example, ``"#48B1FA"``.
Standard three-value, four-value, six-value, and eight-value syntax are all
acceptable.
:return: A :py:class:`~opentrons.protocol_api.Liquid` object representing the specified liquid.
.. versionchanged:: 2.20
You can now omit the ``description`` and ``display_color`` arguments.
Formerly, when you didn't want to provide values, you had to supply
``description=None`` and ``display_color=None`` explicitly.
"""
desc_and_display_color_omittable_since = APIVersion(2, 20)
if isinstance(description, _Unset):
if self._api_version < desc_and_display_color_omittable_since:
raise APIVersionError(
api_element="Calling `define_liquid()` without a `description`",
current_version=str(self._api_version),
until_version=str(desc_and_display_color_omittable_since),
message="Use a newer API version or explicitly supply `description=None`.",
)
else:
description = None
if isinstance(display_color, _Unset):
if self._api_version < desc_and_display_color_omittable_since:
raise APIVersionError(
api_element="Calling `define_liquid()` without a `display_color`",
current_version=str(self._api_version),
until_version=str(desc_and_display_color_omittable_since),
message="Use a newer API version or explicitly supply `display_color=None`.",
)
else:
display_color = None

return self._core.define_liquid(
name=name,
description=description,
Expand Down
2 changes: 1 addition & 1 deletion api/src/opentrons/protocol_api/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def ensure_and_convert_deck_slot(
api_element=f"Specifying a deck slot like '{deck_slot}'",
until_version=f"{_COORDINATE_DECK_LABEL_VERSION_GATE}",
current_version=f"{api_version}",
message=f" Increase your protocol's apiLevel, or use slot '{alternative}' instead.",
message=f"Increase your protocol's apiLevel, or use slot '{alternative}' instead.",
)

return parsed_slot.to_equivalent_for_robot_type(robot_type)
Expand Down
39 changes: 38 additions & 1 deletion api/tests/opentrons/protocol_api/test_protocol_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ def test_home(
decoy.verify(mock_core.home(), times=1)


def test_add_liquid(
def test_define_liquid(
decoy: Decoy, mock_core: ProtocolCore, subject: ProtocolContext
) -> None:
"""It should add a liquid to the state."""
Expand All @@ -1177,6 +1177,43 @@ def test_add_liquid(
assert result == expected_result


@pytest.mark.parametrize(
("api_version", "expect_success"),
[
(APIVersion(2, 19), False),
(APIVersion(2, 20), True),
],
)
def test_define_liquid_arg_defaulting(
expect_success: bool,
decoy: Decoy,
mock_core: ProtocolCore,
subject: ProtocolContext,
) -> None:
"""Test API version dependent behavior for missing description and display_color."""
success_result = Liquid(
_id="water-id", name="water", description=None, display_color=None
)
decoy.when(
mock_core.define_liquid(name="water", description=None, display_color=None)
).then_return(success_result)

if expect_success:
assert (
subject.define_liquid(
name="water"
# description and display_color omitted.
)
== success_result
)
else:
with pytest.raises(APIVersionError):
subject.define_liquid(
name="water"
# description and display_color omitted.
)


def test_bundled_data(
decoy: Decoy, mock_core_map: LoadedCoreMap, mock_deck: Deck, mock_core: ProtocolCore
) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ def __init__(
f"{api_element} is not yet available in the API version in use."
)
if message:
checked_message = checked_message + message
checked_message = checked_message + " " + message
checked_message = (
checked_message
or "This feature is not yet available in the API version in use."
Expand Down

0 comments on commit 837d5ae

Please sign in to comment.