Skip to content

Commit

Permalink
Merge branch 'edge' into app_odd-anonymous-localization-provider
Browse files Browse the repository at this point in the history
  • Loading branch information
brenthagen committed Apr 8, 2024
2 parents 76f191d + f69c2cb commit 48cd622
Show file tree
Hide file tree
Showing 75 changed files with 17,561 additions and 1,096 deletions.
9 changes: 8 additions & 1 deletion api-client/src/protocols/createProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ import { POST, request } from '../request'
import type { ResponsePromise } from '../request'
import type { HostConfig } from '../types'
import type { Protocol } from './types'
import type { RunTimeParameterCreateData } from '../runs'

export function createProtocol(
config: HostConfig,
files: File[],
protocolKey?: string
protocolKey?: string,
runTimeParameterValues?: RunTimeParameterCreateData
): ResponsePromise<Protocol> {
const formData = new FormData()
files.forEach(file => formData.append('files', file, file.name))
if (protocolKey != null) formData.append('key', protocolKey)
if (runTimeParameterValues != null)
formData.append(
'runTimeParameterValues',
JSON.stringify(runTimeParameterValues)
)

return request<Protocol, FormData>(POST, '/protocols', formData, config)
}
8 changes: 4 additions & 4 deletions api/src/opentrons/protocol_api/_parameter_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ def add_float(
parameter = parameter_definition.create_float_parameter(
display_name=display_name,
variable_name=variable_name,
default=default,
minimum=minimum,
maximum=maximum,
choices=choices,
default=validation.ensure_float_value(default),
minimum=validation.ensure_optional_float_value(minimum),
maximum=validation.ensure_optional_float_value(maximum),
choices=validation.ensure_float_choices(choices),
description=description,
unit=unit,
)
Expand Down
39 changes: 38 additions & 1 deletion api/src/opentrons/protocols/parameters/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ def ensure_value_type(
This does not guarantee that the value will be the correct type for the given parameter, only that any data coming
in is in the format that we expect. For now, the only transformation it is doing is converting integers represented
as floating points to integers, and bools represented as 1.0/0.0 to True/False.
as floating points to integers, and bools represented as 1.0/0.0 to True/False, and floating points represented as
ints to floats.
If something is labelled as a type but does not get converted here, that will be caught when it is attempted to be
set as the parameter value and will raise the appropriate error there.
Expand All @@ -72,9 +73,45 @@ def ensure_value_type(
validated_value = bool(value)
elif parameter_type is int and value.is_integer():
validated_value = int(value)
elif (
isinstance(value, int)
and not isinstance(value, bool)
and parameter_type is float
):
validated_value = float(value)
return validated_value


def ensure_float_value(value: Union[float, int]) -> float:
"""Ensures that if we are expecting a float and receive an int, that will be converted to a float."""
if not isinstance(value, bool) and isinstance(value, int):
return float(value)
return value


def ensure_optional_float_value(value: Optional[Union[float, int]]) -> Optional[float]:
"""Ensures that if we are expecting an optional float and receive an int, that will be converted to a float."""
if not isinstance(value, bool) and isinstance(value, int):
return float(value)
return value


def ensure_float_choices(
choices: Optional[List[ParameterChoice]],
) -> Optional[List[ParameterChoice]]:
"""Ensures that if we are expecting float parameter choices and any are int types, those will be converted."""
if choices is not None:
return [
ParameterChoice(
display_name=choice["display_name"],
# Type ignore because if for some reason this is a str or bool, that will raise in `validate_options`
value=ensure_float_value(choice["value"]), # type: ignore[arg-type]
)
for choice in choices
]
return choices


def convert_type_string_for_enum(
parameter_type: type,
) -> Literal["int", "float", "str"]:
Expand Down
15 changes: 11 additions & 4 deletions api/tests/opentrons/protocol_api/test_parameter_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,21 @@ def test_add_float(decoy: Decoy, subject: ParameterContext) -> None:
"""It should create and add a float parameter definition."""
param_def = decoy.mock(cls=mock_parameter_definition.ParameterDefinition)
decoy.when(param_def.variable_name).then_return("my cooler variable")
decoy.when(mock_validation.ensure_float_value(12.3)).then_return(3.21)
decoy.when(mock_validation.ensure_optional_float_value(4.5)).then_return(5.4)
decoy.when(mock_validation.ensure_optional_float_value(67.8)).then_return(87.6)
decoy.when(
mock_validation.ensure_float_choices([{"display_name": "foo", "value": 4.2}])
).then_return([{"display_name": "bar", "value": 2.4}])

decoy.when(
mock_parameter_definition.create_float_parameter(
display_name="abc",
variable_name="xyz",
default=12.3,
minimum=4.5,
maximum=67.8,
choices=[{"display_name": "foo", "value": 4.2}],
default=3.21,
minimum=5.4,
maximum=87.6,
choices=[{"display_name": "bar", "value": 2.4}],
description="blah blah blah",
unit="lux",
)
Expand Down
62 changes: 62 additions & 0 deletions api/tests/opentrons/protocols/parameters/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def test_validate_options_raises_name_error() -> None:
[
(1.0, int, 1),
(1.1, int, 1.1),
(2, float, 2.0),
(2.0, float, 2.0),
(2.2, float, 2.2),
("3.0", str, "3.0"),
Expand All @@ -150,6 +151,67 @@ def test_ensure_value_type(
assert result == subject.ensure_value_type(value, param_type)


@pytest.mark.parametrize(
["value", "result"],
[
(1, 1.0),
(2.0, 2.0),
(3.3, 3.3),
],
)
def test_ensure_float_value(value: Union[float, int], result: float) -> None:
"""It should ensure that if applicable, the value is coerced into a float."""
assert result == subject.ensure_float_value(value)


@pytest.mark.parametrize(
["value", "result"],
[
(1, 1.0),
(2.0, 2.0),
(3.3, 3.3),
(None, None),
],
)
def test_ensure_optional_float_value(value: Union[float, int], result: float) -> None:
"""It should ensure that if applicable, the value is coerced into a float."""
assert result == subject.ensure_optional_float_value(value)


@pytest.mark.parametrize(
["choices", "result"],
[
([], []),
(None, None),
(
[{"display_name": "foo", "value": 1}],
[{"display_name": "foo", "value": 1.0}],
),
(
[{"display_name": "foo", "value": 2.0}],
[{"display_name": "foo", "value": 2.0}],
),
(
[{"display_name": "foo", "value": 3.3}],
[{"display_name": "foo", "value": 3.3}],
),
(
[{"display_name": "foo", "value": "4"}],
[{"display_name": "foo", "value": "4"}],
),
(
[{"display_name": "foo", "value": True}],
[{"display_name": "foo", "value": True}],
),
],
)
def test_ensure_float_choices(
choices: Optional[List[ParameterChoice]], result: Optional[List[ParameterChoice]]
) -> None:
"""It should ensure that if applicable, the value in a choice is coerced into a float."""
assert result == subject.ensure_float_choices(choices)


@pytest.mark.parametrize(
["param_type", "result"],
[(int, "int"), (float, "float"), (str, "str")],
Expand Down
Loading

0 comments on commit 48cd622

Please sign in to comment.